Why Is the Use of '!Important' Discouraged

Why is the use of `!important` discouraged?

There is actual math you can use to predict, control, and reverse-engineer the impact of CSS rules. By using !important you're breaking that. Look at this JS fiddle for example, which doesn't use !important: http://jsfiddle.net/hXPk7/

If you use Firebug or Chrome dev tools to inspect the title element where it says "Richard", you should see these rules, in this order:

/**************************/
/* /hXPk7/show/ (line 20) */
/**************************/
#myExample #title .name {
color: yellow;
}

/********************************************************/
/* /hXPk7/show/ (line 14) - Inherited fromdiv#myExample */
/********************************************************/
#myExample {
color: blue;
}

Note that this is not the order in which they appear in the CSS stylesheet - instead they are ordered in decreasing order of their specificity. The ones which take precedence are listed first, and the others (whose rules are overridden by more specific rules) probably have a property crossed out. This demonstrates that specificity makes it easy to trace (debug?) where an element is getting its CSS properties from.

Now, compare with this JS fiddle - which is effectively the same, but has a single new rule which now uses !important: http://jsfiddle.net/hXPk7/1/

Inspect the same element using Firebug or Chrome dev tools, and you'll see something like this:

/**************************/
/* /hXPk7/1/show/ (line 20) */
/**************************/
#myExample #title .name {
color: yellow;
}

/**************************/
/* /hXPk7/1/show/ (line 26) */
/**************************/
span {
color: black !important;
}

/********************************************************/
/* /hXPk7/1/show/ (line 14) - Inherited fromdiv#myExample */
/********************************************************/
#myExample {
color: blue;
}

Again, the rules are ordered according to their specificity - but note that this time, while the most specific rule which is listed first specifies a color of yellow, the browser instead renders the text as black! This is because the !important declaration has broken the normal behavior of specificity, taking precedence in a way which can be challenging to trace. Imagine a more realistic web site, with potentially hundreds of rules, and the one controlling the color isn't obvious to find, or to change.

Now, maybe this is a problem with the developer tools, but I think it reflects the fact that !important takes a normally easy-to-predict system of precedence and makes it more challenging. Maybe there are times to use it, but it should not be the first tool you reach for when writing CSS.

What are the implications of using !important in CSS?

Yes, I'd say your example of using !important is bad practice, and it's very likely it would cause undesired effects further down the line. That doesn't mean it's never okay to use though.

What's wrong with !important:

Specificity is one of the main forces at work when the browser decides how CSS affects the page. The more specific a selector is, the more importance is added to it. This usually coincides with how often the selected element occurs. For example:

button { 
color: black;
}
button.highlight {
color: blue;
font-size: 1.5em;
}
button#buyNow {
color: green;
font-size: 2em;
}

On this page, all buttons are black. Except the buttons with the class "highlight", which are blue. Except that one unique button with the ID "buyNow", which is green. The importance of the entire rule (both the color and font-size in this case) is managed by the specificity of the selector.

!important, however, is added at a property level, not a selector level. If, for instance, we used this rule:

button.highlight {
color: blue !important;
font-size: 1.5em;
}

then the color property would have a higher importance than the font-size. In fact, the color is more important than the color in the button#buyNow selector, as opposed to the font-size (which is still governed by the regular ID vs class specificity).

An element <button class="highlight" id="buyNow"> would have a font-size of 2em, but a color blue.

This means two things:

  1. The selector does not accurately convey the importance of all the rules inside it
  2. The only way to override the color blue is to use another !important declaration, for example in the button#buyNow selector.

This not only makes your stylesheets a lot harder to maintain and debug, it starts a snowball effect. One !important leads to another to override it, to yet another to override that, et cetera. It almost never stays with just one. Even though one !important can be a useful short-term solution, it will come back to bite you in the ass in the long run.

When is it okay to use:

  • Overriding styles in a user stylesheet.

This is what !important was invented for in the first place: to give the user a means to override website styles. It's used a lot by accessibility tools like screen readers, ad blockers, and more.

  • Overriding 3rd party code & inline styles.

Generally I'd say this is a case of code smell, but sometimes you just have no option. As a developer, you should aim to have as much control over your code as possible, but there are cases when your hands are tied and you just have to work with whatever is present. Use !important sparingly.

  • Utility classes

Many libraries and frameworks come with utility classes like .hidden, .error, or .clearfix. They serve a single purpose, and often apply very few, but very important, rules. (display: none for a .hidden class, for example). These should override whatever other styles are currently on the element, and definitely warrant an !important if you ask me.

Conclusion

Using the !important declaration is often considered bad practice because it has side effects that mess with one of CSS's core mechanisms: specificity. In many cases, using it could indicate poor CSS architecture.

There are cases in which it's tolerable or even preferred, but make sure you double check that one of those cases actually applies to your situation before using it.

White border around page doesn't go away (html, css, js)

_grid.scss is overriding your custom rules because the .container selector they're using is more specific than your wildcard * selector.

You can use the !important qualifier to increase your rules' priority, however be aware that this sort of convention is somewhat discouraged, and in your scenario will cause all elements to have a margin and padding of 0.

Instead, make your selector a bit more specific by changing * to body .container (see below). You should really review Specificity to ensure you understand what exactly is going on here.

const backToTopButton = document.querySelector("#back-to-top-btn");

window.addEventListener("scroll", scrollFunction);

function scrollFunction() {
if (window.pageYOffset > 300) { // Show backToTopButton
if(!backToTopButton.classList.contains("btnEntrance")) {
backToTopButton.classList.remove("btnExit");
backToTopButton.classList.add("btnEntrance");
backToTopButton.style.display = "block";
}
}
else { // Hide backToTopButton
if(backToTopButton.classList.contains("btnEntrance")) {
backToTopButton.classList.remove("btnEntrance");
backToTopButton.classList.add("btnExit");
setTimeout(function() {
backToTopButton.style.display = "none";
}, 250);
}
}
}

backToTopButton.addEventListener("click", smoothScrollBackToTop);

// function backToTop() {
// window.scrollTo(0, 0);
// }

function smoothScrollBackToTop() {
const targetPosition = 0;
const startPosition = window.pageYOffset;
const distance = targetPosition - startPosition;
const duration = 750;
let start = null;

window.requestAnimationFrame(step);

function step(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
window.scrollTo(0, easeInOutCubic(progress, startPosition, distance, duration));
if (progress < duration) window.requestAnimationFrame(step);
}
}

function easeInOutCubic(t, b, c, d) {
t /= d/2;
if (t < 1) return c/2*t*t*t + b;
t -= 2;
return c/2*(t*t*t + 2) + b;
};
body .container {
margin: 0;
padding: 0;
font-family: sans-serif;
}

.container {
width: 100%;
height: 100vh;
scroll-behavior: smooth;
overflow-y: scroll;
scroll-snap-type: y mandatory;
overflow-x: hidden;
min-width:100%;
}

.scroll {
width: 100%;
height: 100vh;
scroll-snap-align: center;
position: relative;
}

/* NAVIGATION BAR */

#main {
width: 100%;
height: 100%;
background-color: green;
}

nav {
width: 100%;
height: 80px;
background-color: #fff;
line-height: 80px;
}

nav ul {
text-align: center;
}

nav ul li {
list-style-type: none;
display: inline-block;
transition: 0.8s all;
}

nav ul li a {
text-decoration: none;
color: gray;
padding: 30px;
}

nav ul li a:hover {
color: #000;
}

/* HOME NAME */

.name {
font-family: sans-serif;
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
text-align: center;
}

/* TYPEWRITER EFFECT */

.css-typing {
position: absolute;
top: 55%;
left: 36.5%;
/*transform: translateX(-40%) translateY(-60%);*/
}

.css-typing p {
border-right: .15em solid orange;
font-family: "Courier";
font-size: 14px;
white-space: nowrap;
overflow: hidden;
}

.css-typing p:nth-child(1) {
/*width: 7.3em;*/
width: 10ch;
-webkit-animation: type 2s steps(10, end);
animation: type 2s steps(10, end);
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}

.css-typing p:nth-child(2) {
width: 38ch;
opacity: 0;
-webkit-animation: type2 2s steps(40, end);
animation: type2 2s steps(40, end);
-webkit-animation-delay: 2s;
animation-delay: 2s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}

.css-typing p:nth-child(3) {
width: 13ch;
opacity: 0;
-webkit-animation: type3 5s steps(20, end), blink .5s step-end infinite alternate;
animation: type3 5s steps(20, end), blink .5s step-end infinite alternate;
-webkit-animation-delay: 4s;
animation-delay: 4s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}

@keyframes type {
0% {
width: 0;
}
99.9% {
border-right: .15em solid orange;
}
100% {
border: none;
}
}

@-webkit-keyframes type {
0% {
width: 0;
}
99.9% {
border-right: .15em solid orange;
}
100% {
border: none;
}
}

@keyframes type2 {
0% {
width: 0;
}
1% {
opacity: 1;
}
99.9% {
border-right: .15em solid orange;
}
100% {
opacity: 1;
border: none;
}
}

@-webkit-keyframes type2 {
0% {
width: 0;
}
1% {
opacity: 1;
}
99.9% {
border-right: .15em solid orange;
}
100% {
opacity: 1;
border: none;
}
}

@keyframes type3 {
0% {
width: 0;
}
1% {
opacity: 1;
}
100% {
opacity: 1;
}
}

@-webkit-keyframes type3 {
0% {
width: 0;
}
1% {
opacity: 1;
}
100% {
opacity: 1;
}
}

@keyframes blink {
50% {
border-color: transparent;
}
}
@-webkit-keyframes blink {
50% {
border-color: tranparent;
}
}

/* SECTIONS */

.box {
width: 100%;
height: 100vh;
padding: 70px;
display: flex;
}

.box .imgPro {
width: 150px;
flex: 0 0 150px;
}

.box .imgPro img {
width: 100%;
padding: 10px;
border-radius: 50%;
}

.box .content {
padding-left: 20px;
}

.box .content h2 {
margin: 0;
padding-left: 0;
padding-bottom: 20px;
text-align: center;
}

/* BACK TO TOP BUTTON */

#back-to-top-btn {
display: none;
position: fixed;
bottom: 20px;
right: 20px;
font-size: 26px;
width: 50px;
height: 50px;
background-color: #fff;
color: #333;
cursor: pointer;
outline: none;
border: 3px solid #333;
border-radius: 50%;
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
transition-property: background-color, color;
}

#back-to-top-btn:hover, #back-to-top-btn:focus {
background-color: #333;
color: #fff;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=devide-width, initialpscale=1.0">
<title> TITLE </title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="style.css">
<!-- link for back to top button -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>

<body>
<button id="back-to-top-btn"><i class="fas fa-angle-double-up"></i></button>
<div class="container">
<div id="main" class="scroll">
<nav>
<!-- <img src="x.png" width="200" height="80"> for top-left logo -->
<ul>
<li><a href="#home" class="js-anchor-link">Home</a></li><!--
--><li><a href="#about" class="js-anchor-link">About</a></li><!--
--><li><a href="#resume" class="js-anchor-link">Resume</a></li><!--
--><li><a href="#portfolio" class="js-anchor-link">Portfolio</a></li><!--
--><li><a href="#contact" class="js-anchor-link">Contact</a></li>
</ul>
</nav>
<h1 class="name">TITLE</a></h1>
</div>
<section id="about" class="scroll">
<div class="box">

<div class="content">
<h2>About</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac gravida nibh. Donec et viverra leo. Sed hendrerit blandit lectus. In pretium orci tellus, porta sollicitudin mauris lobortis et. Donec at sollicitudin nisl. Cras congue elit sed dolor interdum auctor. Nunc convallis purus a vestibulum mollis. Suspendisse ac volutpat sem. Nunc in neque mollis, mattis augue tristique, ornare dolor. Morbi imperdiet tincidunt lectus at molestie. Fusce ultricies mattis maximus.</p>
</div>
</div>
</section>
</body>
</html>

Why is using the singleton pattern discouraged?

How many times a class is instantiated shouldn't be dictated by the class itself, but from an infrastructure that provides the single instance. Singleton makes it impossible to leave this decision to the infrastructure. It is a reusability issue, which shows up for instance in the unit tests, but also when the infrastructure tries to provide another instance for a certain purpose.

(E.g. there is only one database connection. But for importing data from another database, it needs another connection. If the database access service would be a singleton, it is impossible to open another connection.)

Why do CSS Frameworks use !important tags unnecessarily?

If you write your own CSS you have the freedom to add more specific rules whenever needed:

.center        { text-align: center; }
.foobar { text-align: left; }
.foobar.center { text-align: center; }

However, the CSS framework cannot predict how you will arrange your HTML. So it is easier to do !important instead of generating thousands of combinations of more specific rules. Example:

.center               { text-align: center; }
.foobar { text-align: left; }
.barbaz { text-align: right; }
/*
* assuming .center must be centered regardless of other rules and
* !important must be avoided at the same time, we need to do this
*/
.foobar.center { text-align: center; }
.barbaz.center { text-align: center; }
.foobar.barbaz.center { text-align: center; }

Why does jQuery seem to discourage the use of regular OOP?

First crappy Google search for "object oriented javascript" turned this up...but it explains the point I wanted to get across:

JavaScript Object-Oriented Programming

Just take a look at the first paragraph and you find:

Javascript isn't a fully Object Oriented programming language. The use of classes in JS is based on the prototype functionality. The Prototype library masks the use of the prototype functionality to create your class. jQuery expects you to use the prototype functionality the same way you would using regular JS to extend jQuery itself and create your own custom objects.

Is the use of constants in C++ discouraged?

This is inlined with most compilers.

With that said, the style guide is making a point. It says instead of doing this:

#define FOO_MAX_ITERATIONS 25
struct Foo {
void do_it() { for(int i = 0; i < FOO_MAX_ITERATIONS; i++) iterate(); }
};

Should instead be this:

struct Foo {
int getMaxIterations() { return 25; }
void do_it() { for(int i = 0; i < getMaxIterations(); i++) iterate(); }
};

As you can see it's much more consistent and readable in the long run, and good for design down the road, such as when you inherit from the class. Later on, you may want getMaxIterations() to be modified at run-time, and you won't have to do an ugly hack like #define FOO_MAX_ITERATIONS someMethod().

If you're using any sane C++11 compiler (i.e. not Visual Studio), such functions should additionally be declared as so:

struct Foo {
constexpr int getMaxIterations() { return 25; }
void do_it() { for(int i = 0; i < getMaxIterations(); i++) iterate(); }
};

Note constexpr in the declaration of getMaxIterations() there. That tells the C++11 compiler that it is a "constant expression," and it can be evaluated at compile time. By doing this, it can directly replace getMaxIteratsion() with 25 before compiling, among many, many other things, such as allowing you to use it in other compile time declarations.



Related Topics



Leave a reply



Submit