博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
sass编写wxss_用Sass编写简单,优雅且可维护的媒体查询
阅读量:2516 次
发布时间:2019-05-11

本文共 12443 字,大约阅读时间需要 41 分钟。

sass编写wxss

I spent a few months experimenting with for writing simple, elegant and maintainable media queries with Sass. Each solution had something that I really liked, but I couldn't find one that covered everything I needed to do, so I ventured into creating my own: meet .

我花了几个月的时间尝试使用来用Sass编写简单,优雅且可维护的媒体查询。 每个解决方案都有我真正喜欢的东西,但是找不到能够满足我需要做的一切的东西,因此我冒险创建自己的解决方案:满足 。

I started off with this basic list of requirements:

我从基本需求清单开始:

  • Dynamic declaration of breakpoints: I didn't want to have any hardcoded breakpoints in my mixin. Even though I might use phone, tablet and desktop in most of my sites, I might need to add phablet, small-tablet or huge-desktop to my list, depending on the project. Alternatively, I might want to adopt a different approach and have content driving the breakpoints, so I might have bp-small, bp-medium, bp-wide, and so on. To address all this properly, I wanted a simple way to declare the breakpoints I need somewhere in the code (preferably outside the mixin file) and then reference their names to construct the media queries.

    动态断点声明:我不想在mixin中包含任何硬编码的断点。 即使我可能在大多数站点中使用手机平板电脑台式机 ,但根据项目的不同,可能仍需要在我的列表中添加phabletsmall-tabletgreat -desktop 。 或者,我可能想采用其他方法并让内容来驱动断点,所以我可能会有bp-smallbp-mediumbp-wide等。 为了正确解决所有这些问题,我想要一种简单的方法来在代码中的某个位置(最好是在mixin文件外部)声明所需的断点,然后引用它们的名称来构造媒体查询。

  • Simple and natural syntax: My syntax was inspired by , which uses a mixin that receives as arguments the names of the breakpoints preceded by a greater-than or a less-than signs (e.g. @include media(">minWidth")) to indicate whether it's a min-width or max-width.

    简单自然的语法:我的语法受启发,该使用mixin来接收断点名称(以大于或小于符号开头)作为参数(例如@include media(">minWidth") )表示是min-width还是max-width

  • Combine breakpoints with custom values: I often needed to apply additional rules to an element on intermediate breakpoints. Instead of polluting my global list of breakpoints with case-specific values, I wanted to able to throw custom values at the mixin and combine them with my breakpoints (e.g. @include media(">tablet", "<1280px")).

    将断点与自定义值组合:我经常需要对中间断点上的元素应用其他规则。 我希望不使用大小写特定的值污染我的全局断点列表,而是希望能够在mixin处抛出自定义值,并将其与我的断点组合在一起(例如@include media(">tablet", "<1280px") )。

  • Inclusive and exclusive breakpoints: In most of the solutions I've tried, when you make the same breakpoint the upper limit of one media query and the lower limit of another, both media queries will fire when the viewport width is exactly that breakpoint, because all the intervals are inclusive. This can sometimes lead to unexpected behavior, so I wanted to have a finer control over these situations with two additional operators: greater-than-or-equal-to and less-than-or-equal-to.

    包含和排除断点:在我尝试过的大多数解决方案中,当您将一个媒体查询的上限和另一个媒体查询的下限设为相同的断点时,当视口宽度恰好是该断点时,两个媒体查询都会触发所有间隔都包括在内。 有时这可能会导致意外的行为,因此我想通过两个额外的运算符更好地控制这些情况: 大于或等于或 小于或等于

  • An elegant way to include media types and complex expressions: I wanted to be able to specify media types, such as screen or handheld, but as an optional argument because most of the times I'll just omit it. Additionally, I wanted proper support for conditions that contain an or operator (represented by a comma in CSS), such as . Pretty much all of the mixins I've tried fail to properly handle that, because when you combine the expressions a with b or c they generate (a b) or c instead of (a b) or (a c).

    包含媒体类型和复杂表达式的一种优雅方法:我希望能够指定媒体类型,例如screen掌上电脑 ,但作为可选参数,因为大多数时候我都会忽略它。 另外,我希望对包含or运算符(在CSS中用逗号表示)的条件提供适当的支持,例如 。 我尝试过的几乎所有mixin都无法正确处理,因为当将表达式ab or c它们生成(ab) or c而不是(ab) or (ac)

So, basically, I wanted something like this:

所以,基本上,我想要这样的东西:

// We'll define the breakpoints somehow. // For now, let's say tablet' is 768px and 'desktop' 1024px.@include media(">=tablet", "<1280px") {}@include media("screen", ">tablet") {}@include media(">tablet", "retina2x") {}// Compiling to:@media (min-width: 768px) and (max-width: 1279px) {}@media screen and (min-width: 769px) {}@media (min-width: 769px) and (-webkit-min-device-pixel-ratio: 2),       (min-width: 769px) and (min-resolution: 192dpi) {}

Let's get to it then.

那我们开始吧。

解析表达式 (Parsing expressions)

The first step is to come up with a structure where we can define our breakpoints and our media types and expressions. Sass 3.3 added , which are basically multidimensional lists where values can be associated similarly to JSON. This is the perfect structure to accommodate our breakpoints.

第一步是提出一个结构,在其中可以定义断点以及媒体类型和表达式。 Sass 3.3添加了基本上是多维列表,其中的值可以类似于JSON进行关联。 这是适应我们的断点的理想结构。

$breakpoints: (phone: 320px, tablet: 768px, desktop: 1024px) !default;

This is flexible enough to store any number of breakpoints we want, and we automatically label them for easier usage. Because we'll most likely be tweaking these breakpoints on a project basis, we declare it as !default in the mixin and then override the declaration wherever necessary. Similarly, we can use this structure to store our media types and expressions.

这足够灵活,可以存储我们想要的任意数量的断点,并且我们会自动标记它们以便于使用。 因为我们很可能会基于项目调整这些断点,所以我们在mixin中将其声明为!default ,然后在必要时覆盖该声明。 同样,我们可以使用此结构存储媒体类型和表达式。

$media-expressions: (screen: "screen",                     print: "print",                     handheld: "handheld",                    retina2x: ("(-webkit-min-device-pixel-ratio: 2)", "(min-resolution: 192dpi)"),                     retina3x: ("(-webkit-min-device-pixel-ratio: 3)", "(min-resolution: 350dpi)")                    ) !default;

Note that I've declared expressions containing logical disjunctions as nested lists, because we'll have to deal with their conditions individually. We could still declare them as strings separated by a comma, as they are naturally written in CSS, and then break them apart, but we might as well split them at the beginning.

请注意,我已将包含逻辑析取关系的表达式声明为嵌套列表,因为我们将不得不单独处理它们的条件。 我们仍然可以将它们声明为用逗号分隔的字符串,因为它们自然是用CSS编写的,然后将它们拆分开了,但是我们还是最好在一开始就将它们拆分。

The next step is to parse the strings we receive as arguments and translate them into the correct expressions. Instead of trying to write a mixin that does all that at once, let's go for a smaller function that handles a single argument (e.g. >=tablet into min-width: 768px).

下一步是解析我们作为参数接收的字符串,并将其转换为正确的表达式。 与其尝试编写一次完成所有操作的mixin,不如让我们去处理一个处理单个参数的较小函数(例如> = tablet into min-width:768px )。

@function parse-expression($expression) {  $operator: "";  $value: "";  $element: "";  $result: "";  $is-width: true;  // Separating the operator from the rest of the expression  @if (str-slice($expression, 2, 2) == "=") {    $operator: str-slice($expression, 1, 2);    $value: str-slice($expression, 3);  } @else {    $operator: str-slice($expression, 1, 1);    $value: str-slice($expression, 2);  }  // Checking what type of expression we're dealing with  @if map-has-key($breakpoints, $value) {    $result: map-get($breakpoints, $value);  } @else if map-has-key($media-expressions, $expression) {    $result: map-get($media-expressions, $expression);    $is-width: false;  } @else {    $result: to-number($value);  }  // If we're dealing with a width (breakpoint or custom value),   // we form the expression taking into account the operator.  @if ($is-width) {    @if ($operator == ">") {      $element: "(min-width: #{$result + 1})";    } @else if ($operator == "<") {      $element: "(max-width: #{$result - 1})";    } @else if ($operator == ">=") {      $element: "(min-width: #{$result})";    } @else if ($operator == "<=") {      $element: "(max-width: #{$result})";    }  } @else {    $element: $result;  }  @return $element;}

We start by detecting which operator has been used and then match the rest of the string against the breakpoints map. If it matches one of the keys, we'll use its value. If not, we repeat the process for the media expressions map. Finally, if no match is found, we assume it's a custom value in which case we have to cast the string into a number we can use to add or subtract as needed, depending on the operator. I've used to-number from to do that.

我们首先检测使用了哪个运算符,然后将其余字符串与断点图进行匹配。 如果它与键之一匹配,我们将使用其值。 如果没有,我们将对媒体表达式映射重复此过程。 最后,如果未找到匹配项,则假定它是一个自定义值,在这种情况下,我们必须将字符串转换为一个数字,我们可以根据需要使用该数字进行加或减,具体取决于运算符。 我以前经常从进行to-number

处理逻辑析取 (Handling logical disjunction)

Because of the way the or works in CSS, combining conditions containing that operator with others can be quite tricky. For example, the expression a (b or c) d e (f or g) will generate 4 branches of disjoint conditions. Here's a process we can use to generate all those possible combinations:

由于CSS中or工作方式,将包含该运算符的条件与其他条件组合起来可能会非常棘手。 例如,表达式a (b or c) de (f or g)将生成不相交条件的4个分支。 这是我们可以用来生成所有可能组合的过程:

  1. Take a "snapshot" of the expression, leaving singletons untouched and taking only the first element of each or group (a "snapshot" of an expression with no groups is the original expression).

    对表达式进行“快照”,不影响单例,仅获取每个or组的第一个元素(不带组的表达式的“快照”是原始表达式)。

  2. Find the next disjunction (group). Take the expressions already calculated (result) and make (N-1) copies, where N is the number of elements in the group.

    查找下一个析取(组)。 取已计算的表达式(结果)并制作(N-1)个副本,其中N是组中元素的数量。
  3. Replace all the instances of the first element of the group with every other element of the group and update the result.

    用该组的每个其他元素替换该组的第一个元素的所有实例,并更新结果。
  4. Repeat step 2 until there are no more groups.

    重复步骤2,直到没有更多的组。

The following table illustrates the process for the expression shown above.

下表说明了上面显示的表达式的过程。

Iteration Group Result
1 - a b d e f (snapshot)
2 (b, c) a b d e f, a c d e f
3 (f, g) a b d e f, a c d e f, a b d e g, a c d e g
迭代 结果
1个 -- a b de f (快照)
2 (b,c) a b de f ,a c de f
3 [f,g) a b de f ,a c de f ,a b de g ,a c de g

Here's how we can write that in Sass:

这是我们可以在Sass中编写的方法:

@function get-query-branches($expressions) {  $result: "";  $has-groups: false;  // Getting initial snapshot and looking for groups  @each $expression in $expressions {    @if (str-length($result) != 0) {      $result: $result + " and ";    }    @if (type-of($expression) == "string") {      $result: $result + $expression;    } @else if (type-of($expression) == "list") {      $result: $result + nth($expression, 1);      $has-groups: true;    }  }  // If we have groups, we have to create all possible combinations  @if $has-groups {    @each $expression in $expressions {      @if (type-of($expression) == "list") {        $first: nth($expression, 1);        @each $member in $expression {          @if ($member != $first) {            @each $partial in $result {              $result: join($result, str-replace-first($first, $member, $partial));            }          }        }      }    }  }  @return $result;}

Sass doesn't have any string replace function, so I created a simple version that replaces only the first occurrence of the string to be replaced which is what we need:

Sass没有任何字符串替换功能,因此我创建了一个简单的版本,它仅替换第一次出现的要替换的字符串,这是我们需要的:

@function str-replace-first($search, $replace, $subject) {  $search-start: str-index($subject, $search);  @if $search-start == null {    @return $subject;  }  $result: str-slice($subject, 0, $search-start - 1);  $result: $result + $replace;  $result: $result + str-slice($subject, $search-start + str-length($search));  @return $result;}

将所有内容粘合在一起 (Gluing everything together)

Now that we built our little helpers, we can finally write the mixin itself. It'll have to take a variable number of strings, parse them, detect media expressions and handle possible disjunctions and glue everything together to form the media query expression.

现在我们建立了小帮手,我们终于可以编写mixin了。 它必须采用可变数量的字符串,对其进行解析,检测媒体表达式并处理可能的析取并将所有内容粘合在一起以形成媒体查询表达式。

@mixin media($conditions...) {  @for $i from 1 through length($conditions) {    $conditions: set-nth($conditions, $i, parse-expression(nth($conditions, $i)));  }  $branches: get-query-branches($conditions);  $query: "";  @each $branch in $branches {    @if (str-length($query) != 0) {      $query: $query + ", ";    }    $query: $query + $branch;  }  @media #{$query} {    @content;  }}

结语 (Wrapping it up)

This is implementation is a bit complex and some people might argue it's just too much code for writing media queries. Personally, I think this is an easy and comfortable way to write powerful and maintainable media queries with a simple and comfortable syntax, just by downloading and importing a single SCSS file. The GitHub repo is there so people can submit issues and pull requests and that'll hopefully keep the mixin up-to-date with new features and improvements. What are you thoughts?

这种实现有点复杂,有些人可能会认为这是编写媒体查询的太多代码。 就我个人而言,我认为这是一种简单而舒适的方法,只需下载并导入单个SCSS文件,即可使用简单且舒适的语法编写功能强大且可维护的媒体查询。 那里有GitHub存储库,因此人们可以提交问题和提出请求,并希望通过新功能和改进使mixin保持最新。 你有什么想法

翻译自:

sass编写wxss

转载地址:http://klpwd.baihongyu.com/

你可能感兴趣的文章
Redis持久化方式
查看>>
选择器+盒模型
查看>>
进度条2
查看>>
强制类型转换到Number
查看>>
windows内核 内存管理
查看>>
Spring MVC中的DispatcherSevlet和ContextLoaderListener
查看>>
TypeScript 装饰器的执行原理
查看>>
C#之Process
查看>>
菜鸟成长记(十五)----- 要永远相信美好的事情即将发生
查看>>
JDBC
查看>>
CSS选择器
查看>>
HTML结构文档中那些基础又重要又容易被忽略的事?
查看>>
微服务的消费
查看>>
同一台电脑上个人的github账户如何与公司的gitlab账户共存
查看>>
一本通【例题4】Addition Chains——题解
查看>>
E - Cover it!
查看>>
E. 玩游戏
查看>>
mysql 必知必会 -- 一些笔记
查看>>
史上最全阿里 Java 面试题总结
查看>>
Docker命令之 search
查看>>