9 exciting CSS features you can start using today

Avatar Tim Wuyts

By Tim Wuyts

Header image
CSS has been brought to you to revolutionize the visualization of a (responsive) website. However, developers and designers have complained about some particular CSS shortcomings that made commonplace tasks quite the ordeal. Fortunately, the world of CSS is ever-evolving and a lot of new features are being added lately to do away with some of these pesky flaws. We’ll discuss 9 exciting new additions that’ll simplify the styling of web pages. Read on to learn more and start using them creatively today!

1. Scroll snap

You’re navigating down a web page and all of a sudden, scrolling comes to an abrupt halt on a random part of the page, like an image or smack bang in the middle of a paragraph. This is because scrolling inherently lacks precision, something developers have been trying to resolve with JavaScript for ages.

That didn’t always lead to the best results, though, and JavaScript libraries for carousels, animations and horizontal & vertical scroll interactions are CPU-consuming. With the scroll-snap-type CSS property, you’ll give JavaScript the chop! This new module locks the user’s viewport to the part of your website or component you want after the user has finished scrolling. The best part? The effect is completely controlled within CSS.

What’s so cool about it?

Scroll snapping gives you a great option to create transitions and draw the users’ attention to the most important elements of the web page while they’re scrolling. This effect, which has already made an entrance on mobile apps, you can now apply to websites as well without having to resort to JavaScript for any adjustments. You’ll achieve greater precision and a smoother user experience for the end users.

💡 Did you know that over a third of developers haven’t heard of the scroll snap module?
How do you use it?

The scroll-snap-* property is pretty straight-forward. CSS scroll snap has properties for both the parent and container of a component. You simply apply the type of scroll snapping to the container and where its children will snap to. 

The parent or container property determines the direction of the scroll (x, y, block, inline or both) and the behavior of the scroll snap (strictness none, proximity or mandatory). The child property is scroll-snap-align to align the elements when the CSS scroll snap happens.

See the Pen Scroll Snap Demo by Envato Tuts+ (@tutsplus) on CodePen.

2. Container queries

Try to contain your excitement! See what we did there? CSS container queries have finally arrived! They’ve long been on the wish list of many developers and for good reason. 

Media queries are great but they’re not suitable for every single scenario, seeing as they only query the viewport and don’t consider the element’s context. For responsive design, you therefore require separate media queries for every part of the layout, which leads to more cumbersome code. This is where container queries come in! The milestone that finally allows you to style a component according to the size of its parent  container.

Container queries allow you to create responsive components, instead of responsive pages.
What’s so cool about it?

With container queries, components adapt to their context rather than the viewpoint. This approach is game-changing because it lets you reuse the same component in different placements, effectively creating components with a flexible layout. Imagine an e-commerce website and being able to use a single component for the product grid on the main page and the ‘recommended products’ row on every product page.

How do you use it?

First of all, you’ll need to use a container-type or container property (shorthand for container-type and container-name) to define the element as a query container. With the container ready, all you need to do is use @container instead of @media queries. This binds all the styles to the container.

3. CSS custom properties

Sit back and enjoy the read. This still underused feature is about to make your life a whole lot easier! CSS custom properties, often referred to as CSS variables or cascading variables, are a very powerful feature for building complex apps or websites. It hands you incredible flexibility as well as unlocking interesting possibilities. 

Websites are becoming increasingly complex with large amounts of CSS and many values that are repeated in various places. Take, for instance, color themes. If you need to replace a specific color that is used in countless different locations, you’ll have to perform an elaborate search. Custom properties lets you (re)define variables, making it a lot easier to maintain your CSS and achieve cleaner styles.

What’s so cool about it?

No-one likes having to repeat themselves. With custom properties, you can simply update one value and have it reflected in multiple places, avoiding repetition in your CSS. Custom properties are dynamically scoped, which means they’re subject to inheritance and the cascade. You can modify the value of a custom property via media queries, with a pseudo selector such as hover or directly via JavaScript. 

There’s also the benefit of semantic identifiers. For example, --main-text-color is much easier to understand at a glance than #00ff00, especially if this color is also used in other contexts. 

How do you use it?

Custom properties use a double dash prefix. To define a custom property, use the double dash followed by the name you’ve chosen e.g. - - main-text-color. You can then use the var() CSS function to retrieve the value of the property. 

See the Pen Custom Properties Demo: Buttons by Miriam Suzanne (@miriamsuzanne) on CodePen.

4. CSS Grid Layout

CSS hasn’t exactly had the best track record for handling complex layouts. Although this was probably not a big deal at its inception, it became a rather common annoyance. But we’ve already come a long way, from table-based layouts to the creative use of positioning and floats. Today, besides flexbox, we finally also have access to a grid layout that will completely change the way you design user interfaces!

CSS Grid Layout offers a flexible and responsive two-dimensional grid layout that makes it easier to build more complex layouts using columns and rows.

Discovered Subgrid yet?

It's a helpful new feature of the Grid Layout module which lets you define a child grid that will inherit its parent’s layout. The difference with nesting is that, while the parent’s layout is applied to the subgrid, the subgrid can still override aspects of the layout if necessary.

What’s so cool about it?

One major advantage of CSS grids is that they ensure real separation of layout and content. The visual order of elements on the page is disconnected from the order of elements in the markup (HTML code). This means that you can optimize the accessibility of the markup independent of the visual result. A change to either the content or the layout will not affect or break the other. 

The grid itself is completely defined within CSS. Aside from the parent HTML element the grid is applied to, there’s no need to define any additional elements for the columns, rows, cells or areas. So designers, for instance, can experiment with new layouts using only CSS. You don’t have to change the markup (HTML code) to change the position of an item using the CSS grid.  

Here’s another improvement. Instead of having to finagle with (negative) margins and paddings, you get to use the gap property! This feature, which defines the gaps between rows (row-gap) and columns (column-gap), is not only available in CSS Grid Layouts but also in combination with Flexbox.

How do you use it?

To define a grid, you only need one HTML element: the grid parent container. That’s the element the layout is going to be applied to. You can create a grid container through the display property with the value of grid or inline-grid. Then you set the column and row sizes with grid-template-columns and grid-template-rows. All direct children of grid containers become grid items. Their source order doesn’t matter, you can simply use media or container queries to rearrange your grid.

See the Pen CSS Grid Layout: Going Responsive iii by Envato Tuts+ (@tutsplus) on CodePen.

💡 Did you know?

With CSS Grid Layout comes a new flexible unit: the Fr unit. Fr is a fractional unit and 1fr is for 1 part of the available space. The Fr unit will help you create an organized and responsive grid.

5. CSS Logical Properties and Values

Sometimes it’s the little things that make a big difference! Now, with CSS Logical Properties, you’re able to control the layout through logical, rather than physical, directions and dimension mappings

These new shortcuts are useful for borders, but you can also use the inline and block, start and end logical keywords in many other properties. For instance, when you’re creating a website in multiple languages and you need to consider writing modes and text direction.

What’s so cool about it?

Instead of having to fuss with each physical direction separately, you can use the convenient shorthands provided by the CSS logical properties to efficiently set left and right, or top and bottom margins, borders and paddings. See the example below. 

These shortcuts are mainly very useful if you’re creating a website in multiple languages and you have to consider multiple text-directions and/or writing-modes. Logical properties and values use terms to define the direction in which they flow. Inline is the dimension along which a line of text is written in the type of writing used. E.g. in an English document, the text is horizontal from left to right. In Japanese, however, the inline dimension is vertical because the writing mode is vertical. The block dimension reflects the order of the blocks on the page. In English, they’re vertical, whereas in any vertical writing mode, they’re executed horizontally. 

How do you use it?

When you want to talk about left and right, use inline. When you want to refer to top and bottom, use block. 

For instance, when you’d have tried to center something, you might’ve written something like this:

See the Pen Logical Properties Demo by Andy Bell (@andy-set-studio) on CodePen.

Similarly, the margin-block property sets both margin-top and margin-bottom. And this feature is not limited to margins. Logical properties provide similar shorthands to set border, padding, sizes, … 

6. Aspect Ratio

Getting the dimensions of an element on a web page just right has always been a major concern for designers and developers. After all, it’s really important for the user experience. But whenever you tweak the final width of the element, you also need to adjust the height. Trying to get an element to look perfect on various devices could therefore be a frustrating affair. 

This new CSS property allows you to set the aspect ratio of an element. When you set the width of an element, the height of the element is automatically calculated to match the provided ratio. The dimensions are then adjusted for different screen sizes, maintaining a responsive design across devices.

What’s so cool about it?

The aspect-ratio feature is especially useful for images, videos and iframes that need to take on specific dimensions like 1:1, 16:9, etc. It saves you the hassle of setting a fixed width and height of an element and changing them for different screen sizes for responsive layouts or using cumbersome hacks to enforce a certain ratio. All you need to do is set an aspect ratio and set either the width or the height (or even none). CSS will then take care of the calculation for you.

Here’s an example of when the default behavior of the aspect-ratio feature is of use to you. Take, for instance, a call to action that consists of a component with text on one side and an image on the other side. If you set an aspect ratio on the image, the text column will grow tall enough at least to match the height of the image. If, however, the text is longer, the image will expand to match the height of the text.

How do you use it?

See the Pen Aspect ratio demo by Joshua Comeau (@joshwcomeau) on CodePen.

Some example ratios:

  • a ratio of 1/2: the height of the element is twice the width of the element

  • 16/9: the element's height is 9/16 times the element's width.

  • 1/1: the element's height is the same as the element's width.

  • You can also use floating numbers. Instead of fraction 1/2, you can use 0.5.

7. CSS Cascade Layers

You’ve written a new CSS rule and you check your browser only to notice that your style change hasn’t gone through. Maybe there’s a conflict with another CSS rule that’s got a higher specificity? Or you might’ve used a third-party library with style rules that collide with yours? To avoid a big mess (like littering rules with !important’s) in an attempt to regain control, there is the new Cascade Layers feature.

This feature lets you override some CSS styles to avoid style conflicts. CSS uses selector specificity and order of appearance to decide which styles will be applied to which element. Styles with higher specificity can also override styles with lower specificity. For larger projects, it’s nearly impossible to keep track of all the style definitions and that’ll inevitably lead to conflicts. CSS Cascade Layers is the ultimate solution to resolve conflicts between multiple sources of styles.

What’s so cool about it?

Regardless of how you write CSS, you’re still working within the author origin. That means you’re dealing with specificity and order of appearance as the determining factors to work out the right style to apply to an element. 

Through the use of @layer, you’ll decide how styles from varying sources are evaluated and prioritized. This means that you’re able to create your own custom CSS layers that determine the specificity hierarchy of all your CSS code, including external styles.

How do you use it?

Create your custom layers in the desired order. To define a layer, use the @layer keyword followed by the layer name. Then put all your CSS code inside curly brackets, {}. The layers are all entirely separated from one another. 

Like in Figma or Adobe Photoshop, the last defined layer or lowest layer in CSS will be the first in the list of layers in the visual and will have priority over the other layers. It’s considered to be more specific in the layer hierarchy and all the styles in that layer will therefore override styles from the higher layers, even if a selector in the higher layer has higher specificity.

To append CSS code to your layers, you can define the same layer again using @layer. This doesn’t affect the order of the layers as the hierarchy is defined by the initial code that created the layers. The only difference is that, this way, you’re able to add extra styles to a particular layer.

8. CSS Selectors - :is(), :where() & :has()

When you write CSS, you’ll often end up with long selector lists to select the HTML elements you want to target with the same style rules. To avoid having to write out all the combinations as separate selectors, CSS has introduced the new pseudo-class selectors :is(), :where() and :has(). This shortens the list of selectors and allows you to reduce repetition in your markup.

What’s so cool about it?

Pseudo-class selectors like :is(), :where() and :has() select elements based on a specific state. :is() and :where() are handy new selectors that let you group elements together in the middle, beginning or end of a selector, improving the legibility of your markup. They also give you the power to nullify or increase specificity. :has(), on the other hand, is a powerful new selector that lets you match some elements more finely based upon its children, also described as the much anticipated parent selector.

:is() and :where()

:is() and :where() are pretty much identical in that they check whether the element in its position in the outer selector matches any of the selectors in its selector list. Where they differ, is that :is() takes the specificity of its most specific selector whereas the specificity of :where() is always zero, making it easier to override.


With :has(), an element is only selected if it contains at least one element that matches the selector you pass into the :has() function. For instance, a:has(img) selects all <a> elements that contain an <img> child. It’s essentially a parent selector, but with some additional perks! 

For example, imagine being able to select all <div>s but only when they contain a <p>. Or you could style an image differently in a <figure>, depending on whether it’s accompanied by a <figcaption> or not. The possibilities are nearly endless. 

How do you use it?

9. CSS User Preference Queries

Delivering a top-notch user experience is what it’s all about! These exciting CSS features make it easier for you to take into account different user needs and create a customized experience. Some of these features are especially important when it comes to improving web accessibility.

Motion-heavy websites, for instance, are not always desirable! It’s important to realize that not everyone experiences motion the same way. Some people may have disabilities or get negatively affected. For them, movement can result in migraines, nausea, loss of balance or even seizures. Websites with a lot of motion might also drain the battery life of mobile devices much faster or use up more data. It’s therefore essential to always consider user preferences.

What’s so cool about it?

Does your user tend to use touch rather than a mouse? Are they sensitive to animations or would they prefer a dark theme over a light theme? A few characters of code is all it takes for you to accommodate their needs and enhance their user experience.


This media query detects whether these users have activated the reduced motion preference in order to minimize the amount of movements and animations. The values consist of either no-preference, which means that there is no known user preference, or reduce, which means that the user has indicated that they prefer an interface with minimum movement. 


This media feature detects whether a user has requested a dark or light color theme. The user indicates their preference through an operating system setting (e.g. light or dark mode) or a user agent setting. The default value is a light color theme.


Interaction is about how the user interacts with the web page. This media query detects the input used by the user e.g. mouse, pen, touch, … You can set a media query based on a user’s pointing device and whether they can hover over elements on the page. 

For example, common use cases for interaction media features could include making controls bigger/smaller depending on whether the user has a touchscreen device or is using a mouse. Or only using a CSS dropdown menu if the user has an input that allows him or her to hover over certain elements.

How do you use it?

See the Pen User preference queries demo from Jecelyn by Ergün Erdoğmuş (@ergunsh) on CodePen.

Crafting a user-centric experience for the future

CSS is thriving and while every system inevitably has its drawbacks, new developments are continuously emerging to make the lives of developers and designers significantly easier. These new features help you create cleaner designs and more efficient code, while also encouraging you to embrace the flexibility of the web and to be mindful of user browsing behaviors

Websites are becoming increasingly more complex and users have a whole array of devices at their disposal to scour the web. Frameworks that were conceived several years ago are evolving in response to the many changes that are taking place. It’s not about whether something can be done. It’s about understanding the tools you have at your disposal and it’s about keeping the user at the heart of your development decisions.

Want to learn more from our Dev colleagues?

Go ahead, hit that button and check out our vacancies!

You'll learn from the best, we guarantee that.