how to translate similar codes to a function in co

2019-01-20 16:57发布

问题:

I want to add some common vars in my scss file, such as mgb10 for margin-bottom:10px; pdl20 for padding-left:20px;
my method is very stupid. how to improve my code using a sass function.

回答1:

bookcasey gave a great answer to the OP's question, but I'm not convinced the right question was asked. Here's the problem with @extend in the scenario you've drawn out with your example code and why it probably isn't the right choice.

Let's start with these little guys here, they look like ones we are likely to use pretty often:

%mgt10 { margin-top: 10px }
%mgb10 { margin-bottom: 10px }
%mgl10 { margin-left: 10px }
%mgr10 { margin-right: 10px }

We start coding along and end up using them a lot:

.body { @extend %mgt10; @extend %mgb10; @extend %mgr10; @extend %mgl10; font: 12px/1.4 sans-serif }

.error { @extend %mgt10; color: red; padding: 10px; }

.cool-button { @extend %mgt10; border: 1px solid }

hr.awesome { @extend %mgt10; color: blue }

This is what our short Sass file will generate (316 bytes):

.body, .error, .cool-button, hr.awesome {
  margin-top: 10px; }

.body {
  margin-bottom: 10px; }

.body {
  margin-left: 10px; }

.body {
  margin-right: 10px; }

.body {
  font: 12px/1.4 sans-serif; }

.error {
  color: red;
  padding: 10px; }

.cool-button {
  border: 1px solid; }

hr.awesome {
  color: blue; }

You wouldn't actually write your CSS that way, would you? @extend is working against you in this case because it is generating far more selectors than you actually need (and it only gets worse the more selectors you have extending any given class and the fewer the number of lines in said class being extended -- imagine 30 selectors extending %mgt10, how about 50?). You've taken DRY to the extreme and as a result, you've given up readability on the Sass side and conciseness on the CSS side.

Let's try another route:

$default-gutter-size: 5px;

@function gutter($width, $size: $default-gutter-size) {
    @return $width * $size;
}

.body { margin: gutter(2); font: 12px/1.4 sans-serif }

.error { margin-top: gutter(2); color: red; padding: gutter(2); }

.cool-button { margin-top: gutter(2); border: 1px solid }

hr.awesome { margin-top: gutter(2); color: blue }

We get essentially the same CSS, but without all of the extra selectors and we still have the ability to use shorthand (as an added bonus, we can use our function on things that aren't margins if we really want) (228 bytes):

.body {
  margin: 10px;
  font: 12px/1.4 sans-serif; }

.error {
  margin-top: 10px;
  color: red;
  padding: 10px; }

.cool-button {
  margin-top: 10px;
  border: 1px solid; }

hr.awesome {
  margin-top: 10px;
  color: blue; }

Don't get me wrong, @extend is great, but it is best used for extending classes with a fair number of attributes, not just 1 or 2. Part of using a CSS Preprocessor is knowing when to use which feature to get the best result.



回答2:

Here is a Sass mixin (you can change it to Scss) that uses the @for directive to generate all the placeholder selectors:

=shorthander($property: margin, $shorthand: mg)
  @for $i from 0 through 4
    $multiple: $i*5
    %#{$shorthand}#{$multiple}
      #{$property}: $multiple*1px

+shorthander()
+shorthander(margin-top, mgt)
+shorthander(margin-right, mgr)
+shorthander(margin-bottom, mgb)
+shorthander(margin-left, mgl)

div
  @extend %mgt20

Demo



标签: sass