CSS Logical Properties, easier with Sass
On This Page:
Using logical properties when writing CSS allows your code to adapt more naturally to various text directions and writing modes, such as left-to-right (LTR), right-to-left (RTL), or even vertical text.
Unlike traditional properties like margin-left
or padding-top
, logical properties help future-proof your designs by removing assumptions about content flow and the needs of your site visitors.
Rather than thinking in fixed directions, logical properties enable your designs to adapt automatically. This improves both consistency and flexibility, making your CSS more scalable and versatile for the different contexts it may encounter.
The problem with logical properties
They can be long, really long.
Whilst logical properties are a fantastic way forward offering flexibility and adaptability, they can introduce a level of verbosity that can make your code appear more cumbersome. Instead of using margin-left
, you would need to write margin-inline-start
, which can feel longer and less intuitive.
Going all in on using logical properties and as more are used, such as border-block-end-width
, border-inline-start-color
, the increased verbosity can make your stylesheets harder to read and potentially harder to maintain.
Let’s make things easier with Sass
One approach to handle the potential verbosity and cognitive load of using logical properties is to make use of the (still) widely used preprocessor, Sass. Using logical properties can feel to repetitive and could require extra thought as you translate the more traditional properties into their newer logical counterparts.
By using Sass with its functions, maps, variables, and mixins, you can simplify the syntax, reduce any possible mental overhead, and allow for more readable, reusable, and intuitive code that will automatically handle the complexity of logical property mapping.
The Sass we need
When thinking about how I could use the features of Sass to make it easier to write CSS logical properties I thought about what properties to work with and what CSS values to be able to apply.
Although CSS logical properties go way beyond these examples, I thought It would be good to limit the amount of options to the CSS I write day-to-day that could benefit from these mixins. This boiled down to margin
, padding
, border
and it’s derivatives including border-radius
as it’s slightly different as it’s more ‘corners’ thant ‘sides.
I also thought that we should be able to allow the author to write in several ways which are: a raw CSS value, a Sass $variable
(we’re using Sass after all) or a CSS custom property.
Deciding on this as ‘the brief’ I started to work on writing the code.
A function for values
In a Sass mixin, passing through a raw CSS value or Sass $variable
is relatively straightforward but when it comes to using CSS custom properties in Sass you will eventually have to deal with interpolation. I wanted the value an author prescribes to be as less taxing as possible. I wanted an author ot be able to write
40px
$padding-size-l
--margin-size--0
To avoid having to write the interpolation and for the author not to have to write var()
each time I created a small little Sass function that checks the start of the $value
, if it contains --
then it will return the $value
as a CSS custom property wrapped in var()
. If the value doesn’t contain --
at the start it simply returns the value.
Creating maps for cleaner mixins
My first efforts in creating a Sass mixin had me using the @if
and @else
Sass control directives.
An author could then write:
which would output in a stylesheet as:
Although the person authoring may never need to touch or see these mixins I think it would be cleaner, and less repetitive when writing more mixins to make use of Sass maps. We want to be able to not just port the complexity of the @if
/ @else
statement to the Sass map but to simplify the possibilities so we can reuse the map as much as possible.
As we will be wanting to use these logical property Sass mixins for padding
, margin
, and border
we can create a Sass map and mixins to not need those words.
Instead tying the Sass map to margin, for example:
We can simplify it and let the Sass mixin do some work:
With the above Sass map we can reuse it in our mixins for border
, margin
, and padding
.
Making the mixin
So, we have our Sass function that works out if the $value
passed is a CSS custom property or not and we have a Sass map that helps the simplifying and tying together of traditional CSS properties and the newer logical properties. We need a mixin to put it all together.
So for the following examples I will concentrate on just on of the possible mixins. A Sass mixin for easier logical properties for with margin.
We want our Sass mixin to take two variables: the $side
that we want the rule to change and the $value
of how much to apply. To determine if the Sass mixin is dealing with a raw CSS value, a Sass $variable
or a CSS custom property we want the $value
to go through our function we have created. To determine which $side
we want to effect and have the correct logical property printed out in CSS we need fetch that correct value from the map. Then, if the $side
value is correct (top,bottom,left,right) we want to generate the CSS.
We would then write out similar mixins for the padding and border rules.
Using the mixin
Now we have the Sass function, map, and mixin we can then use it in our codebase:
Which would generate this CSS:
border-radius hits different
As I previously mentioned unlike CSS properties for rules like margin and padding that affect the sides of an element on the page border-radius
logical properties effect the corners and because of this the syntax may seem a little odd. Rather than border-top-left-radius
with logical properties you can write border-start-start-radius
.
Michelle Barker has a great article about logical properties and border-radius
that is well worth reading.
To make use of Sass to simplify writing CSS for border-radius
using logical properties we can still use the Sass function above, but we will need a new Sass map to accommodate the different syntax and another mixin to generate the final code.
For the Sass map we can write something similar to the $logical-map
map we created earlier.
As the CSS for the border-radius
is written differently to something like margin
or padding
we would need a new Sass mixin that accommodates this, putting the logical property between border-
and radius
. This is a relatively simple re-jig of the Sass mixin we have already created.
Wrapping up, I hope this post highlights how Sass can be a powerful tool for managing CSS logical properties in your everyday workflow. By leveraging Sass to handle the potential verbosity and complexity of logical properties, you can keep your codebase clean and easier to maintain, even as your designs scale and evolve. This approach simplifies the process, ensuring your CSS remains adaptable and efficient, without getting bogged down by repetitive or lengthy syntax.
You can start using the Sass Logical Properties package right away, or if you’re curious about how it works, head over to the GitHub repo to view the source code. With these tools, you’ll find working with logical properties far more manageable in your next project.
I realise that while Sass simplifies logical properties, adding a build step isn’t always the easiest solution for everyone. However, for those already using Sass, it can help reduce complexity, improve maintainability, and enhance readability.