CSS Overrides: Friend or Foe?
转自:http://www.callumhart.com/blog/css-overrides-friend-or-foe
Anyone familiar with CSS will know how fragile it can be.
Changes to CSS must be made carefully. An innocent change can bring unforeseen and unwanted side effects: styles that are neither expected nor wanted. Adding or removing styles, re-ordering rule-sets, changing selector specificity, using important - all of these can break things.
The behaviour of CSS is both unpredictable and unreliable. A combination that means we cannot confidently make changes. Something that passed QA yesterday can be broken tomorrow.
So what changed in the interval? Well, there could be two reasons:
- Undesirable styles were added
- Desirable styles were removed
These sound simple, and easy to avoid. However, if this is the case why is the frequency of breakages among CSS so high?
The answer is architecture and more specifically, overrides.
This statement may seem bold. Why would overrides contribute to CSS side effects given the language seems to encourage them. Even from a clean slate user-agent styles need overriding.
body {
margin: 0px; // reset user-agent style
}
More often than not, the first styles we author override the defaults supplied by browsers. It therefore seems reasonable to continue this approach and adopt this architecture in our own styles going forward. Any style we want to "undo" is overridden.
We leverage the cascade, fine-tune specificity, and when all else fails use !important.
Problems with Overrides
As CSS projects grow the convenience and appropriateness of overrides soon fades.
Our focus shifts from desirable styles - those visible to users, to fighting off undesirable styles - those that need undoing. The overriding architecture that once seemed harmless and even endorsed by the language becomes a real problem.

We learn the hard way that it is overrides, and not CSS that are fragile and unpredictable.
Overrides are fragile because they rely on CSS and HTML, both of which are vulnerable to change. Changes in CSS directly impact which styles “win”. Changes to HTML structure and attributes can introduce previously non-existent overrides.
Overrides are unpredictable for several reasons:
- Global scope permits anyone to override.
- The side effects aren’t immediately apparent (exaggerated by #1).
- A lack of encapsulation dampens efforts to protect styles from being overridden.
- The longevity of an override is unknown. Just because a style wins today doesn’t mean it always will.
- They obfuscate developer intent. It’s hard to differentiate between an intentional and unintentional override, which can be left to interpretation.
These, plus the self-perpetuating nature of overrides leads to a catch–22 situation, in which the more overrides exist the more overriding you need to do. It feels safer to override an unwanted style than remove it. Once committed overrides are hard to escape.
There is a correlation between the volume of overrides and the time and energy spent managing them. I'd tentatively suggest a similar correlation exists between the number of overrides and UI bugs.
Finally, when two or more styles compete there is only one winner - never a draw. End users only get to see the styles that win. The time invested in styles that lose (those that are overridden) plus the extra overhead of managing overrides doesn’t seem to pay off.
So Why Override?
If overrides are so bad why do we keep using them?
The first reason we’ve already touched on. CSS encourages overrides by teaching us the way to avoid undesirable styles is to override them. This fuels the perception that overrides are integral to CSS, despite their pitfalls.
However, in reality the only mandatory overrides are those that undo user-agent styles. Other usages are voluntary. We choose to bite the poisoned apple.
Further fuel is added since there isn’t anything to prevent overrides. This not only reinforces overrides are okay, but also allows them to happen. Other languages keep users in check by enforcing rules. If something shouldn’t happen we know about it. For example, in JavaScript you cannot change the value of a const through re-assignment. Browsers and runtimes tell us this shouldn’t happen, and more importantly, prevent it from happening.
const color = "cadetblue";
color = "transparent";
// TypeError: invalid assignment to const 'color'
Sometimes the choice to override simply isn’t our own.
Not all overrides are intentional. It’s very easy to accidentally override a style without being aware of it happening. Nothing informs us an intentional or accidental override has occurred. Overrides operate silently, many of which go unnoticed until they need undoing.
So what can be done?
The most popular CSS strategies around today share one thing in common:
They all reduce overrides.
BEM uses naming conventions to modularise CSS, leveraging name-spaces to encapsulate styles. CSS Modules implements local scope, where styles in one file cannot override styles in another. CSS-in-JS solutions such as styled components generate unique classes to avoid selectors clashing. Styletronassigns every unique CSS declaration to an atomic class.
Despite the implementation differences each approach converges in regards to overrides: the less overrides exist, the more robust and predictable CSS is. Which begs the question: if fewer overrides are better, why override at all?
It's time to invest in winning styles.
Introducing Immutable Styles - a new library that removes overrides from CSS. A place where all styles win.
Immutable Styles
Parallels can be drawn between mutability in programs and overrides in CSS. An override mutates the value of an existing style. For example:
p {
color: cadetblue;
}
p {
color: transparent; // override the color
}
Since the second rule-set has equal specificity and comes later in the cascade it wins. The original color of the paragraph is modified from cadetblue to transparent. This represents the usual behaviour of CSS - all styles are mutable - all styles can be overridden.
Immutable Styles introduces the concept of immutability to CSS.
In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created.
An immutable style cannot change after it is created - it can never be overridden. Any attempt to mutate (override) a style is not allowed. The CSS example above simply isn't possible when using immutable styles. The library detects the override and throws a compile-time error:
[Override Found] the "color" of "p" has already been defined
The "color" of "p" is defined here:
color: cadetblue;
and again here:
color: transparent;
The "color" of "p" cannot be overridden
This type of instant feedback is incredibly powerful. Both intentional and unintentional overrides become immediately apparent. Reminiscent of the const re-assignment example earlier - if a style attempts to override another style we know about it, and more importantly it is prevented.
Whether an override happens in the same file or in another file, among equal selectors or nested selectors, or even among different screen-sizes, immutable styles catches them all:
[Override Found] "nav ul.menu button.btn--primary" overrides the "color" set by "button.btn--primary"
Overridden styles ("button.btn--primary"):
color: skyblue;
Overriding styles ("nav ul.menu button.btn--primary"):
color: salmon;
The "color" of "button.btn--primary" cannot be overridden
Immutable styles make CSS predictable. Operating in the global environment is safer, since changes can no longer introduce accidental overrides. We can guarantee the value of a style will never change. In immutable styles the color of button.btn--primary will always be skyblue.
Immutable styles make CSS robust. The effectiveness of styles is no longer reliant on cascade, specificity and importance (things very prone to change). The outcome and longevity of styles becomes resilient to changes in both HTML and CSS. Encapsulation by design encourages us to organise and namespace styles accordingly.
Immutable styles solves problems by making things simpler. Keeping track of overrides is no longer a developer concern. The complex task of detecting and preventing overrides is offloaded to a compiler. The laborious task of reasoning with overrides - determining what override is intentional or not - is completely eliminated. The era of manually managing overrides is over.
So, could the era of CSS overrides be over?
***
This post was inspired by my research and work on Immutable Styles (and its predecessor, mono). Still in beta, the project is very welcome to feedback, fresh perspectives, new feature requests, and of course, contributors
CSS Overrides: Friend or Foe?的更多相关文章
- [转]phoneGap3.0安装步骤(以windows下的android环境为例):
phoneGap3.0安装步骤(以windows下的android环境为例): 环境: WIN系统,JDK,Android,Eclipse,Ant,Git,PhoneGap3.x (Cordova) ...
- Technical analysis of client identification mechanisms
http://www.chromium.org/Home/chromium-security/client-identification-mechanisms Chromium > Chro ...
- PhoneGap搭建运行环境(3.2版本)
一. 1.准备环境nodejs(http://nodejs.org/download/) 2.ant(http://ant.apache.org/bindownload.cgi) 3.Android ...
- Cordova(PhoneGap) 环境搭建与基础
Cordova(PhoneGap) 创建步骤:官方Guide 环境准备 安装 Node.js nodejs.org 安装 git git-scm.com (bin目录添加到path) 安装 cordo ...
- todomvc-app
1.HTML <!doctype html> <html lang="en"> <head> <meta charset="ut ...
- 利用calibre抓取新闻
Adding your favorite news website calibre has a powerful, flexible and easy-to-use framework for dow ...
- hybird app(混合式app开发)cordova ionic 创建相应平台的app
hybird app(混合式app开发) 之ionic 框架平台 guide cordova 创建相应平台的app 1. npm install -g cordova //全局安装cordova-cl ...
- 框架入门经典项目TodoMVC
一.项目介绍 ①地址:http://todomvc.com/ ②GitHub下载模板 ③通过npm下载模板的样式 ④通过npm下载Vuejs ⑤项目文件,主要修改app.js和index.html两个 ...
- Vue.js学习TodoMVC小Demo
实现效果如下: 把玩了添加和删除功能,代码如下: index.html: <!doctype html> <html lang="en"> <head ...
随机推荐
- VSTO:使用C#开发Excel、Word【1】
<Visual Studio Tools for Office: Using C# with Excel, Word, Outlook, and InfoPath >——By Eric C ...
- 怎样在Ubuntu 14.04中安装Java(转)
想知道如何在Ubuntu 14.04中安装Java?安装Java肯定是安装Ubuntu 14.04后首先要做的几件事情之一(见http://www.linuxidc.com/Linux/2014-04 ...
- EffecJava Method
坚持使用Overrider注解,可以预防我们并没有重载的情况出现. 除非使用者绝对安全,不然使用保护性拷贝,可以使程序安全. public class Period {//没有拷贝安全 private ...
- [SpringMVC-值传递] 初始SpringMVC--SpringMVC中的值传递
把页面中输入的值传递到后台以及后台向前台传递,有以下几种方式 这里以登录为例子,实现打印前端页面的值 1,新建一个控制器,根据不同的请求地址实现不同的请求方式 LoginController.java ...
- shell脚本实例-内存磁盘使用警告
1,磁盘使用警告并发送邮件 #!usr/bin/bash #df -Th|grep '/$' 这个是获取内存使用的那一条记录 #后面两句是获取内存的使用率 disk=`df -Th|grep '/$' ...
- webrtc 音频一点相关知识
采样频率: 44.1kHz ,它的意思是每秒取样44100次 .8kHz 8000次, 16kHz 160000次 比特率: 比特率是大家常听说的一个名词,数码录音一般使用16比特 ...
- js继承中,原型属性的继承探究
最近研究了js的继承,看了幻天芒的文章http://www.cnblogs.com/humin/p/4556820.html#3947420,明白了最好是使用apply或call方法来实现继承. 已知 ...
- linux的python版本升级
可利用Linux自带下载工具wget下载,如下所示: # wget http://www.python.org/ftp/python/2.7.3/Python-2.7.13.tgz 下载完成后 ...
- 用optional取代null
Java8引入了java.util.Optional<T>,它是一个封装的Optional值的类.变量存在时,Optional类只是对类简单封装.变量不存在时,缺失的值会被建模成一个空的O ...
- foreach遍历数组、数组的转置与方阵的迹
public class Copy1 { public static void main(String[] args) { array1(); //如果不初始化元素,默认为0 int [][] a = ...