Does sass harm performance?

2019-03-25 19:33发布

问题:

I've been educating myself. Reading this:

The engine evaluates each rule from right to left, starting from the rightmost selector (called the "key") and moving through each selector until it finds a match or discards the rule. (The "selector" is the document element to which the rule should apply.)

For example:

ul li a {...}
#footer h3 {...}
* html #atticPromo ul li a {...]

Now, some example code SASS outputs for me:

#content #blog {
  /* ... */
}
/* line 85, ../sass/screen.scss */
#content #flickr {
  /* ... */
}

#content #flickr div p {
  /* ... */
}

This seems a bit awkward.. am I doing something wrong? Is this a communication problem between me and Sass? Are we losing it?

Edit: Some SCSS code:

#flickr {
    @include columns(5,8);
    background: url('../img/ipadbg.png') no-repeat;

    #ipod-gloss {
        z-index: 999;
        position: relative;
    }

    div {
        margin-top: -80px;
        margin-right: 20px;

        h2 {
            color: $white;
            font-size: 24px;
        }

        p {
            margin-top: 40px;
        }
    }
}

Side Bonus!: The article says browsers (or at least Firefox) search the selectors from right to left. I couldn't understand why this is a more efficient why. Any clues?

回答1:

You have to find your compromise between maintainability (nesting makes it easier to find your way around in the stylesheet) and rendering performance.

A rule of thumb says you should try to restrict yourself to a three-level nesting and you should avoid to nest IDs if it's not necessary.

However, I think nesting too much is not the biggest issue. As soon as I became aware of the power of mixins, I used them a lot.

For example, this is my often used button mixin:

@mixin small-button($active-color: $active-color, $hover-color: $button-hover-color, $shadow: true)
  display: inline-block
  padding: 4px 10px
  margin:
    right: 10px
    bottom: 10px
  border: none
  background-color: $button-color
  color: $font-color-inv
  +sans-serif-font(9px, 700)
  text-align: center
  text-transform: uppercase
  cursor: pointer
  @if $shadow
    +light-shadow
  &:hover
    text-decoration: none
    background-color: $hover-color
  &:last-child
    margin-right: 0
  a
    color: $font-color-inv
    &, &:hover
      text-decoration: none
  &.disabled
    +opacity(0.75)
    &:hover
      background-color: $button-color
  &.active
    background-color: $active-color
    &.disabled:hover
      background-color: $active-color

You see, quite a bit code. Applying such mixins to many elements on your page will result in a big CSS file which takes longer to be interpreted.

In the old fashioned CSS-way you would give each button element e.g. the class .small-button. But this method pollutes your markup with unsemantic classes.

Sass provides a solution though: selector inheritance via the @extend directive.

If you set defaults for your parameter of the mixin, you can also provide a simple class, which uses the mixins with your default:

// Use this mixin via @extend if you are fine with the parameter defaults
.small-button
  +small-button

And then you can just inherit from this class in various contexts:

#admin-interface
  input[type=submit]
    @extend .small-button

The resulting CSS statement aggregates all usages of .small button into one rule with comma-separated selectors:

.small-button, #admin-interface input[type=submit] {
  display: inline-block;
  ...
}

Concluding, a naive usage of Sass can effect your CSS performance. Used wisely, however, it is maintainable thanks to well-structured and DRY code, it leads to proper separation of markup and styling (semantic classes only) and allows for smart and performant CSS code.



回答2:

SASS is only a language that compiles down to CSS. If you're concerned with SASS' performance in terms of how it runs in the browser, then SASS doesn't enter the equation -- it'll be compiled and served to the browser as regular CSS.


From what I can see of your usage of SASS, there's a couple of things I could suggest:

  1. You don't have to nest everything.

The ability to nest rules inside each-other in SASS is a language feature, but you don't have to do it if it doesn't make sense to do so.


In terms of your general CSS usage:

  1. If the nesting gets too severe/unwieldly, consider using classes where it makes sense.
  2. When it's necessary to use the hierarchy of DOM elements, consider using the [child combinator]: .foo > .bar.

IDs are meant to be unique, thus should always only reference a single element. Most of the time, they can be CSS rules unto themselves -- #content #flickr would become just #flickr, for instance -- and browsers will optimise the lookup for a single ID. The only time you would need something like #id1 #id2 is if #id2 needs to appear in different contexts on different pages.

If your selector contains things like #id div p, that div is either superfluous or serving a specific purpose.

  • If it's superfluous, change the rule to #id p, which selects any <p> that occurs as a descendant of #id.
  • If it serves a specific purpose, consider classing the <div> with a class name that describes its purpose -- perhaps <div class="photos-list">. Then your CSS could become .photos-list p, which is far more maintainable and reusable.