CSS Myths

CSS gets a lot of stick, the internet is full of articles describing ways to fix one, or all of it’s so called failings. Most of the time however, these criticisms are unfair, untrue or both. This post aims to highlight some of the common misconceptions or myths around CSS and it’s capabilities.

1) CSS is broken

So first of all CSS is not broken, it just isn’t a programming language and so should not be expected to behave like one. Many of the CSS in JavaScript methodologies that have appeared over the past couple of years aim to ‘fix’ CSS by forcing it to behave in a more conventional programming way, in doing so some key CSS features are lost.

You can read more on the topic of broken CSS in these two awesome articles…

2) CSS is easy

CSS is not easy, it may be seen as the simplest of the client side languages, but creating a maintainable CSS code base at scale is a difficult skill to master. Like no other front end language any changes made in CSS have the potential to affect the global landscape, meaning extra discipline and knowledge are required.

To work effectively a detailed understanding of key CSS features is essential:

i. Cascade

The cascade determines which properties will be applied, and can be thought of as a way of resolving conflicting styles. Which selector wins out in the cascade depends on three factors:

  • Importance
  • Specificity
  • Source order

On larger projects a misunderstanding of the cascade can lead to excessive use of the !important rule as well as unmaintainable CSS.

ii. Importance

There are three origins of styles, each one has a level of importance used by the cascade to determine which properties will be applied.

  1. Author
  2. User
  3. Default (User agent or browser style sheet)

This order can be reversed by using the !important rule allowing a property in the user style sheet to override a matching declaration in the author stylesheet.

iii. Specificity

Specificity comes into play if the importance of two declarations is the same. A 4 digit number is given to each selector, this number is derived from the 4 factors below, the selector with the higher specificity will be applied.

  1. Inline styles (Style attribute)
  2. The number of ID’s in the selector
  3. The number of classes, attributes and pseudo-classes in the selector
  4. The number of elements and pseudo-elements in the selector

Examples:

#nav .selected > a:hover // Specificity = 0,1,2,1
.wrapper .box ul li // Specificity = 0,0,2,2

The !important rule is not directly related to specificity as it does not have a value assigned to it. It does however automatically win out against any other selectors. The only way to override and !important deceleration is to use another !important declaration on a selector of equal or higher specificity.

iv. Source order

Source order comes into play if the importance and specificity of two declarations is the same. Declarations that appear at the bottom of a style sheet will effectively overwrite any matching declarations from above.

v. Inheritance

CSS properties like font-family and color can be applied to a single element and be passed down to the elements children. Inheritance can be controlled using three CSS properties:

  • inherit
  • initial
  • unset

A directly targeted element will always take precedence over rules which an element inherits from its ancestor.

3) Global scope is a bad thing

CSS is often compared unfavourably to the localised scoping features of JavaScript. A misunderstanding of the global scope leads to an overuse of the !important declarations and excessively long selectors (both of which introduce a new set of problems). However, the global by default feature of CSS is actually a great asset, if you know how to use it. The cascade and inheritance together determine how all elements will be styled, this allows you to create base level rules just once and have them applied across a projects code base.

Benefits of the CSS global scope include:

  • New pages or features are instantly styled
  • Typography and spacing are consistent
  • Design patterns are consistent
  • CSS is re-usable
  • CSS remains scalable and easy to update

4) There is no local scope

CSS, where required can be scoped, the simplest method for this would be by using double classes and a naming convention such as BEM to target a specific chunks of UI.

// Default button
.button {
display: inline-block;
text-align: center;
background-color: #00823b;
color: #fff;
}
// Success button
.button--success {
background-color: #005ea5;
}
// cancel button
.button--cancel {
background-color: $primary-color--featured;
}

You can also add scope to your CSS using custom properties. Custom properties, allow values to be saved and re-used throughout a project. In that respect they are similar to Sass or Less variables, but have the added bonus of being dynamically updated (More on this in section 9).

Custom properties are defined like this…

:root {
--button-color: #ffa600;
}

and used like this…

.button {
background-color: var(--button-color);
}

Custom properties can be scoped by declaring values inside a class or element. In the below example the value assigned to the buttons background colour is changed for all elements within a header block.

:root {
--button-color: #ffa600;
}
header {
--button-color: #aaa19a;
}
.button {
background-color: var(--button-color);
}

5) if you use important! you’re writing bad CSS

It is true that an over-reliance on the !important rule can be a warning sign for underlying issues with the CSS architecture, but providing it is used responsibly and for it’s intended purposes it is perfectly fine to use.

Firstly by using the !important declaration rules from the author style sheet are able to be overwritten in the user style sheet. This is particularly useful for accessibility enhancements such as increasing font size or re-adding the underline property to anchors.

!important can also be used effectively in the author style sheet itself, the most common use case is for utility (helper) classes. Utility classes are often used to set up base rules for a project, these are rules which should always be applied, yet are usually defined at the top of a style sheet and have low specificity.

.margin-bottom {
margin-bottom: 10px;
}

The specificity of the selector above is just 0,0,1,0 and so the value could be easily overwritten further down the style sheet. To address this and make helper classes more resilient the !important rule can be applied.

.margin-bottom {
margin-bottom: 10px!important;
}

Finally, although not a valid long term use case the !important rule can be very useful for getting quick fixes shipped to production. There isn’t always time for a detailed assessment of the CSS structure or for re-factoring large chunks of code to fix a style bug. In these cases it can be helpful to use !important as a make shift fix, providing the real work is addressed afterwards. It is usually helpful to keep these styles in a separate CSS file, csswizardry.com has more information on this concept.

6) There is no feature detection

Progressive enhancement promotes the idea of adding extra functionality for modern browsers and devices, only after delivering core content and functionality to all bowsers and devices. This is often achieved with JavaScript feature detection.

It is possible to detect support for a property within CSS without the need to include a third-party script such as Modernizr or Autoprefixer. The @supports rule is a conditional rule which allows for different styles to be applied depending on browser support.

By defining core css properties at the top of a selector you ensure they are rendered in all browsers, extra ‘nice to have’ features can be conditionally added underneath without effecting this core styling.

An example would be CSS blend modes which are used to add styling to backgrounds and images. This could create problems with the readability of overlaying text in browsers that don’t support blend modes.

By using @supports you can ensure browsers without support are served a more appropriate font-color.

.banner {
background-image: url(image-url);
color: black
@supports (background-blend-mode: multiply) {
.banner {
background-color: green;
background-blend-mode: multiply;
color: white
}
}

You can also check for features which are not supported as well as combine properties with either ‘and’ or ‘or’ statements.

7) CSS is just for making things pretty

CSS can do more than simply apply the aesthetics to an applications UI. It can also play a role in enhancing the accessibility and usability of a project.

CSS can among other things also be used to…

  • Enhance the readability of written content
  • Improve the readability of anchor tags
  • Provide navigation assistance with active and visited classes
  • Provide screen reader specific content such as ‘Skip to content’ links
  • Ensure hidden content isn’t picked up by screen readers with a visibility:hidden; class
  • Insert descriptive text for icons or external links…
a[target=_blank]::after {
display: inline-block;
overflow: hidden;
width: 0;
height: 0;
white-space: nowrap;
content: '(opens new window)';
}

8) Shorthand is better

Shorthand properties allow multiple values to be set simultaneously and are a nice way of keeping your style sheets concise and readable. There are currently 6 shorthand property groups:

  • font
  • background
  • margin
  • border
  • padding
  • list

There can be performance gains from using the shorthand syntax correctly, for example…

margin-top: 10px;
margin-right: 0;
margin-bottom: 10px;
margin-left: 0;

could be written as…

margin: 10px 0;

However, it is important to note that a property which is not specified is automatically set to its initial value. This can lead to properties needing to be overwritten further down the style sheet. For example…

html {
font: 16px Helvetica Neue
}

will actually set…

html {
font-style: normal;
font-variant: normal;
font-weight: normal;
font-size: 16px;
line-height: normal;
font-family: Helvetica Neue;
}

On larger applications problems can arise from setting too many styles to soon, in the example above it would be more efficient to set only the values that we are using…

html {
font-size: 16px;
font-family: Helvetica Neue;
}

9) CSS doesn’t have functions

CSS is defined as a markup language not a programing or scripting language, but it does come with some basic functions included The most common functions deal with colour manipulation and animations, functions like linear-gradient(), blur(), translate() and rotate().

One of the more powerful functions is calc() which can be used to replace number values with simple mathematical equations. Calc() also allows for mixed units making it an effective way to build native responsive layouts.

.sidebar {
width: 300px;
}
.content {
width: calc(100% - 300px);
}

Using custom properties can open up new possibilities for functions within CSS. Unlike Sass or Less variables, which compile to set values in CSS, custom properties can be updated dynamically. This allows for direct interaction between CSS and JavaScript. The below JavaScript allows a CSS custom property value to be retrieved or set…

var backgroundColor = bodyStyles.getPropertyValue('--background-color'); // Retrieve
body.style.setProperty('--background-color', 'black'); // Set

Example use cases for dynamic CSS include Generating colors, Contrast theming and Animation

10) Frameworks are bad

There are literally hundreds of CSS frameworks, grids and methodologies available to speed up development and help lay the foundations for scalable well structured CSS. These frameworks can be hugely beneficial but are often heavily criticised.

A few common criticisms are:

  • They discourage beginners to learn the basics of CSS
  • The markup is not semantic
  • The CSS is bloated and often unnecessary for smaller projects
  • Framework CSS is overwritten in the project code

Despite these concerns frameworks can help improve a project. The important thing is that you understand how and why the framework works, and that it adds value to your project. It’s important that the framework is seen as a helper and not as an essential component. It’s wise to use only the parts of the framework that you need, strip out the excess and make changes where required.

In summary

In summary CSS is not a bad programing language, its a very good style sheet language. The features of CSS are not secret, anyone can read up on and learn to write good CSS, if you choose not to it can become a nightmare.