Code Monkey home page Code Monkey logo

Comments (23)

adamwathan avatar adamwathan commented on May 20, 2024 76

@jbrooksuk: Two main reasons I will personally always prefer Less over Sass:

1. Evaluation order

Less is evaluated like a declarative definition of your styles (just like CSS is), while Sass is evaluated like a procedural script.

Consider this example:

.btn {
    color: blue;
    border-color: currentColor;
    color: red;
}

When the above CSS is applied, the border color will be red, not blue, because the final evaluated value of the selector's color property is red.

Consider this Sass:

.btn {
    $color: blue;
    border-color: $color;
    $color: red;
}

In that example, the border color will be blue, because Sass evaluates your styles from top to bottom like a procedural script, using whatever the state of each variable is along the way.

Here's the same thing in Less:

.btn {
    @color: blue;
    border-color: @color;
    @color: red;
}

Just like real CSS, in Less, the border-color here will be red, not blue, because Less evaluates your styles and uses the final evaluated variable value.

This problem rears its head in many ways in Sass, including the stupid !default hack that was eventually introduced because of how sensitive Sass is to inclusion order and evaluation order.

The order in which styles are defined already has important semantic meaning in CSS. Selectors that are defined later will defeat selectors that are defined earlier that have the same specificity.

So with Sass, you have an on-going battle between two different reasons to define things in a certain order, making your stylesheets more complicated and more difficult to maintain.

You also have to change your entire mental model of how styles are defined because Sass does not work like CSS, whereas Less works exactly like CSS.

Another example, in Sass, mixins need to be defined before they are used:

.foo {
    @include bg-primary();
}

@mixin bg-primary() {
    background: green;
}

// ERROR: Undefined mixin 'bg-primary'.

In Less, this works perfectly fine:

.foo {
    .bg-primary();
}

.bg-primary() {
    background: green;
}

// Sure bro, I got your back! 😎

This might seem like an arbitrary choice at first, but when you compare it with how CSS works, it becomes obvious that Less is more consistent the expected behavior of real CSS.

For example, keyframes can be defined after they are used with no problem at all:

.this-spins {
    animation: spin 500ms infinite linear;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

Again, this is because CSS is a declarative definition of your styles, and Sass is a procedural script evaluated with state and control flow.

This sort of inconsistency means that when someone is learning Sass, they are building an incorrect mental model of how CSS works, and for that reason I think it's better to use Less, which behaves the same way CSS does.

More reading:

2. Classes as mixins

A crucial feature in Less that I rely on every day is the ability to use a class as a mixin.

Say I have these utility classes defined:

.py-2 {
    padding-top: .5rem;
    padding-bottom: .5rem;
}

.px-4 {
    padding-top: .5rem;
    padding-bottom: .5rem;
}

.bg-primary {
    background-color: @color-primary;
}

.text-medium {
    font-weight: 600;
}

.text-light {
    color: #fff;
}

(...along with many others.)

I might combine those utilities in my markup to style a button:

<button class="bg-primary text-medium text-light py-2 px-4">Save</button>

Over time, maybe I find myself using this same combination of utilities fairly regularly as a standard button style.

"Graduating" this pattern of classes to a component in Less is trivial, because classes in Less are composable:

utilities-to-component

Here's the resulting definition for the .btn class:

.btn {
    .bg-primary;
    .text-medium;
    .text-light;
    .py-2;
    .px-4;
}

...which compiles to:

.btn {
   background-color: @color-primary;
   font-weight: 600;
   color: #fff;
   padding-top: .5rem;
   padding-bottom: .5rem;
   padding-top: .5rem;
   padding-bottom: .5rem;
}

In Sass, you have a few options:

1. Extend your utilities

Here's a quick example with fewer declarations:

.btn {
    @extend .bg-primary;
    // ...
}

.bg-primary {
    background: blue;
}

This will generate the following CSS

.bg-primary, .btn {
    background: blue;
}

This might seem fine at first glance but look at this example:

.btn {
    @extend .bg-primary;
    // ...
}

.btn-warning {
    background: yellow;
}

.bg-primary {
    background: blue;
}

...which generates:

.btn-warning {
    background: yellow;
}

.bg-primary, .btn {
    background: blue;
}

Notice how the declaration of .btn is now below the declaration of .btn-warning?

That means that in this HTML, the button will be blue, not yellow:

<button class="btn btn-warning">Save</button>

So you can't extend a utility unless you define that utility earlier as well, which means the utility won't defeat component styles unless you add !important. Or you could use silent classes/placeholders, but you end up with the same out of control verbosity that you'll see in the next example.

This is grim as fuck, don't use @extend in Sass or in Less.

More reading:

2. Build your utilities out of mixins

Another option is to create an explicit mixin for every single utility class so you can reuse that mixin in the new component:

@mixin py-2() {
    padding-top: .5rem;
    padding-bottom: .5rem;
}

@mixin px-4() {
    padding-top: .5rem;
    padding-bottom: .5rem;
}

@mixin bg-primary() {
    background-color: $color-primary;
}

@mixin text-medium() {
    font-weight: 600;
}

@mixin text-light() {
    color: #fff;
}


.btn {
    @include bg-primary();
    @include text-medium();
    @include text-light();
    @include py-2();
    @include px-4();
}

.py-2 {
    @include py-2();
}

.px-4 {
    @include px-4();
}

.bg-primary {
    @include bg-primary();
}

.text-medium {
    @include text-medium();
}

.text-light {
    @include text-light();
}

This is so much more work than it is in Less that there's no way I could ever justify it.

This approach to composing components out of repeated patterns of utilities is the basis of my entire philosophy to CSS, so I can't use a pre-processor that makes it this hard to do.

More subjective reasons

A few other things I much prefer in Less:

1. Mixin syntax

Compare Sass:

@mixin text-truncate() {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.card-heading {
    @include text-truncate();
}

to Less:

.text-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.card-heading {
    .text-truncate;
}

Less crap to type is better than more crap to type IMO.

2. Functional vibe

Less feels more "sophisticated" to me than Sass. I like that I can use pattern matching, guard clauses, and recursion instead of if statements and loops. It's more fun and feels like a functional programming language. Helps keep me sharp :)

Closing

I prefer Less because it is evaluated declaratively instead of procedurally, supports class composition, and feels more like a functional programming language.

Sass has a handful of features that Less doesn't have, but I've never found myself needing them. Less does the features that I do need better than Sass does them for my workflow, so I will take Less to the grave with me :)

from horizon.

adamwathan avatar adamwathan commented on May 20, 2024 32

Sass is awful, Less is much better 🤷‍♂️

from horizon.

uikid avatar uikid commented on May 20, 2024 24

-1

Fact: Less roxx more. Look at @adamwathan's #56 (comment)

Just to clarify why I originally wrote "no explanation needed": @lucasmichot said BS 4 will use SASS. What kind of explanation is that? So I just adjusted my comment to @lucasmichot's scope. There are plenty of great frameworks/tools that use LESS.

from horizon.

rtablada avatar rtablada commented on May 20, 2024 4

@adamwathan on the topic of:

Less crap to type is better than more crap to type IMO.

Those code blocks aren't equivalent though.
In SASS:

@mixin text-truncate() {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.card-heading {
    @include text-truncate();
}

Will output:

.card-heading {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

While your LESS example:

.text-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.card-heading {
    .text-truncate;
}

Will output:

.text-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.card-heading {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

This means unused mixins/utilitiy classes are still output in the final CSS.
This is not a bug, but something to be aware of in the way the syntax has ambiguity.

from horizon.

adamwathan avatar adamwathan commented on May 20, 2024 3

This means unused mixins/utilitiy classes are still output in the final CSS.

You can easily avoid this by throwing parentheses at the end of the utility name:

.text-truncate() {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

Personally I want them generated and output though because I use them all over my markup.

EDIT: Another way you can avoid them being rendered is using @import (reference) and putting the utilities in a different file. Can be handy if you want to use classes from a third party library as mixins without outputting them. Used to do that with Bootstrap a lot.

from horizon.

themsaid avatar themsaid commented on May 20, 2024 2

I really hope we used BS4 in Horizon :)

from horizon.

themsaid avatar themsaid commented on May 20, 2024 2

@lucasmichot css doesn't like css, css only likes to piss off people.

from horizon.

kbirmhrjn avatar kbirmhrjn commented on May 20, 2024 2

Hey @adamwathan just publish it in your blog already. Too much detail just to be in github comment section.

from horizon.

lucasmichot avatar lucasmichot commented on May 20, 2024 1

@jbrooksuk you would be more than welcome
I have never been enjoying CSS - and CSS doesn't like me either 😅

from horizon.

mikeerickson avatar mikeerickson commented on May 20, 2024 1

@adamwathan I know your love for less is well know, but this information makes it more fact than a simple "I use less because it is better than sass" general statement.

@kbirmhrjn I am actually glad it was here, as it is fits into the overall ticket request (which had a lame simple "because it is better") vibe. And the fact that BS4 uses it is a baseless reason.

from horizon.

rtablada avatar rtablada commented on May 20, 2024 1

I would say the variable evaluation is a philosophical difference and I see both sides of things.

The idea of LESS working more like CSS variables today is a 👍 if you know how CSS variables work:

body {
  --card-bg-color: #fff;
}

.card {
  background: variable(--card-bg-color);
}

body {
  --main-bg-color: brown;
}

Would result in the card's background being brown.
However saying that it's good for LESS to treat it this way is a bit of misnomer since ☝️ doesn't tell the whole story.

In the example above, the card background is brown because it is inside of body and body has the custom variable --main-bg-color set to brown at last evaluation.
But, there's a lot more to understand since variables are scoped to the local parent element so if there's a parent element to .card that changes the value of --main-bg-color then the card's background is no longer brown but something else entirely.
This is something that without a component CSS implementation is near impossible to replicate statically.

In that IMO the last value evaluation used by LESS actually makes for a different mental model and something that could cause unexpected bugs.

Let's take the card from above:

@cardBg: #fff;

.card {
  background: @cardBg;
}

Now in a later imported file the @cardBg value is changed:

@cardBg: green;

.author-bio-thing {
  background: @cardBg;
}

This has now created side-effects throughout the application that could be hard to trace especially in an OSS environment.

That's not to say that SASS is perfect in either of these senses since later imports inherit the changed variable value.
But, I think it matches a simpler mental model:

$red = "#f00";
echo("body: " . $red);
$red = "#e34242";

The code would print body: #f00 not body: #e34242

from horizon.

adamwathan avatar adamwathan commented on May 20, 2024 1

I think the difference is that Sass is a scripting language with state, Less is an evaluated declarative definition of your styles. Sass is easier to understand if you want to think of your styles like a programming script, Less is easier to understand if you are used to CSS.

Another example of order declaration in Less matching CSS is keyframes; in CSS keyframes can be defined after they are used, all that matters is that they exist at the end of the day when the stylesheet is being evaluated. Less works the same way, processing your CSS using one final state, not a ton of intermediate state.

from horizon.

tillkruss avatar tillkruss commented on May 20, 2024

Yeah, good idea. Laravel and BS v4 use Sass, let's stick with the same stack.

from horizon.

jbrooksuk avatar jbrooksuk commented on May 20, 2024

I'm quite happy to implement this if no-one else wants to?

from horizon.

jbrooksuk avatar jbrooksuk commented on May 20, 2024

Ok! On it 😊

from horizon.

lucasmichot avatar lucasmichot commented on May 20, 2024

😂😂😂😂 ❗ 🤣

from horizon.

 avatar commented on May 20, 2024

LESS is.... less than favorable.

from horizon.

jbrooksuk avatar jbrooksuk commented on May 20, 2024

On what basis @adamwathan? For consistency, Laravel is Scss :)

from horizon.

lucasmichot avatar lucasmichot commented on May 20, 2024

1tatq2

from horizon.

jbrooksuk avatar jbrooksuk commented on May 20, 2024

@adamwathan thanks for the in-depth analysis :)

from horizon.

lucasmichot avatar lucasmichot commented on May 20, 2024

Yes @adamwathan 👍

from horizon.

rtablada avatar rtablada commented on May 20, 2024

Sass is easier to understand if you want to think of your styles like a programming script, Less is easier to understand if you are used to CSS.

That puts the difference in mindset. I personally see it as SASS is aware that it's a static compilation target, LESS is still inheriting from being a browser runtime language. While there are things that LESS is more like CSS running in browser, there are still alot of ways where it stops short and I find those edges can be harder to grasp than a scripting/compilation style model that SASS provides.

from horizon.

juukie avatar juukie commented on May 20, 2024

Nice details about the differences. Thanks all!

from horizon.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.