Published  | 6 min read

Ten nifty (S)CSS tips

I've been working with CSS (specifically Sass) for several years now and I'm a big fan of the language. It's fun and the possibilties with CSS has grown quite steady in the past few years and you also have to rely less on JavaScript for certain tasks. Here are a few ten, hopefully helpful, tips in part one of my mini-series of CSS tips.

Contents

  1. Children Margin
  2. border-radius
  3. z-index Map
  4. Counters
  5. Units
  6. Attribute Selectors
  7. pointer-events
  8. Size Mixin
  9. object-fit
  10. all

#1 Children Margin

I don't like to set margins globally on elements like headlines or a <p>. Instead I select all children, except the last one, of a parent and set the bottom margin to get a nice, consistent spacing.

.parent > *:not(:last-child) {
  margin-bottom: 25px;
}

I use this a lot and to save some lines, I defined a handy SCSS mixin:

@mixin children-margin($margin) {
  > *:not(:last-child) {
    margin-bottom: $margin;
  }
}

.parent {
  @include children-margin(25px);
}

#2 border-radius

You can define more than just four values for border-radius to create some funky shapes. You can even animate these values as seen on this CodePen.

.fancy-box {
  border-radius: 30% 70% 80% 20% / 40% 20% 80% 60%;
}

Learn more about it in this blogpost or try out the generator.


#3 z-index Map

To actually keep track of all the z-index values used across a project, I recommend using a Sass map. Here's how to write a map:

/**
 * <key>: <value>
 */

$z-index: (
  header: 5,
  mobile-menu: 10,
  overlay: 15
);

I usually increment the values by 5, but anything is fine. Just keep the numbers readable. 😁 I use a short Sass function to get the value from the map and then set it for the z-index property.

@function z($element) {
  @return map-get($z-index, $element);
}

.header {
  z-index: z(header);
}

#4 Counters

It's possible to count with CSS! The parent needs the counter-reset property and the value can be set to any name. The given name then can be used on the content of pseudo elements (::before and ::after) of the children. The only thing left to add is counter-increment on the pseudo element so it actually counts up.

<section class="counters">
  <div class="box">
    First box
  </div>
  <div class="box">
    Second box
  </div>
</section>
/**
 * Any name is possible, it doesn't have to be 'counter'
 * This way you can define multiple, different counters
 */

.counters {
  counter-reset: counter;
}

.counters > div::before {
  content: '' counter(counter) '';
  counter-increment: counter;
}

#5 Units

There are a lot of other, practical units you can use in CSS. It's time to step aside, px, % and em. 😛

rem

The rem unit is the most useful unit for font sizing. The r in rem stands for root; this is equal to the font-size set at the root element, which in most cases is the <html> element.

html {
  font-size: 20px;
}

h1 {
  font-size: 3rem; // equals 60px
}

vh and vw

The v in both units stand for viewport. One unit equals to 1% of the width/height of the viewport's initial containing block. A simple way of doing full-height elements can be achieved with a single line:

section {
  height: 100vh;
}

It's not recommended to set a width of 100vw because the scrollbar is included as a part of the viewport and will create a horizontal scrollbar.

turn

A turn unit is exactly one full circle. This unit is a good fit for rotation.

.tumbleweed {
  transform: rotate(0.5turn); // same as 180deg
}

#6 Attribute Selectors

There are many ways to select specific elements, attribute selector is one of them. The syntax for a attribute selector is super flexible, here are a few examples:

/**
 * Elements beginning with 'important' in the data-tag attribute
 */

[data-tag^='important'] {
  background-color: red;
}

/**
 * Links that end in '.com'
 */

a[href$='.com'] {
  color: blueviolet;
}

/**
 * Class attribute that contains the word 'icon-' anywhere
 */

[class*='icon-'] {
  width: 20px;
  height: 20px;
}

/**
 * Class attribute that contains the complete word 'logo'
 */

[class~='logo'] {
  opacity: 0.9;
}

These selectors also work in JavaScript and can help to select elements you want to filter, for example.

const cheeses = document.querySelectorAll('[data-tag="cheese"]');

Check out more examples on MDN.


#7 pointer-events

The pointer-events property can be set to none and allows an element to not receive any events. Instead the event will occur on the elements behind it.

.headline-over-slider {
  pointer-events: none;
}

#8 Size Mixin

I like to define Sass mixins for properties I have to write often and to go from 2-5 lines to only one. This mixin is, as you've probably guessed, for setting the size of an element. You don't have to pass a second value if the width + height needs to be of the same size.

@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}

.box {
  @include size(200px, 150px);
}

.icon {
  @include size(25px); // width and height is set to 25px
}

#9 object-fit

If you want to align differently sized images, set a fixed width + height and use object-fit: contain. The images will be aligned perfectly and won't be stretched anymore. You can also set object-fit: cover, which works similarly to background-image: cover.

img {
  width: 150px;
  height: 150px;
  object-fit: contain; // <3
}

#10 all

The last tip, short and sweet. You can quickly reset the default browser styling of elements by setting all: unset on the <body> (or only on certain elements). Be aware that IE + Edge does not support this property, but it's still quite handy when you need a quick CSS reset and want to test something.

body {
  all: unset;
}

I hope you find these tips just as useful as I did. So long!