CSS Selectors
CSS selectors are the building blocks of CSS. They define the elements to which a set of CSS rules apply. Understanding selectors is crucial for effective CSS coding. Below are the detailed list of selectors.
Type Selector
Or also called as Tag Selector, targets HTML elements based on their tag name.
p {
color: red;
}
This will apply the style to all <p>
elements.
Class Selector
Targets elements based on their class
attribute.
.highlight {
font-weight: bold;
}
HTML: <p class="highlight">This is bold.</p>
ID Selector
Targets a specific element based on its id
attribute.
#header {
font-size: 24px;
}
HTML: <div id="header">This is the header.</div>
Attribute Selector
Targets elements based on an attribute and its value.
[href="https://google.com"] {
text-decoration: none;
}
Pseudo-class Selector
Pseudo-class selectors in CSS are used to target elements based on their state, position, or other characteristics that can't be targeted using simple selectors. Pseudo-classes are preceded by a single colon (:
).
:hover
Targets an element when the mouse is placed over it.
a:hover {
color: blue;
}
:active
Targets an element during the activation state, like when a link or button is being clicked.
button:active {
background-color: green;
}
:focus
Targets an element when it gains focus, such as an input field when clicked on.
input:focus {
border-color: red;
}
:nth-child()
Targets elements based on their position within a parent element.
li:nth-child(odd) {
background-color: grey;
}
:not()
Targets elements that do not match the given selector.
p:not(.special) {
color: red;
}
:first-child
and :last-child
Targets the first or last child of a parent element.
li:first-child {
font-weight: bold;
}
:disabled
and :enabled
Targets form elements that are disabled or enabled.
input:disabled {
background-color: lightgrey;
}
:visited
and :link
Targets link elements that have been visited or not.
a:visited {
color: purple;
}
MDN document on Pseudo class selectors
Pseudo-Element Selectors
::first-letter
Targets the first letter of a block-level element.
p::first-letter {
font-size: 2em;
font-weight: bold;
}
::first-line
Targets the first line of a block-level element.
p::first-line {
text-transform: uppercase;
}
::before
Inserts content before an element's actual content.
p::before {
content: "Note: ";
font-weight: bold;
}
::after
Inserts content after an element's actual content.
p::after {
content: " (end)";
font-style: italic;
}
::placeholder
Targets the placeholder text in form fields like input
and textarea
.
input::placeholder {
color: gray;
}
::selection
Targets the portion of an element that is selected by the user.
p::selection {
background-color: yellow;
}
MDN document on psuedo element selectors
Combinators
In CSS, combinators are used to define relationships between different elements based on their position in the HTML document. They allow you to create more specific and complex selectors. Here are the primary types of combinators:
Descendant Combinator (Space)
This is the most straightforward combinator. It selects all elements that are descendants of a specified element.
Example 1: Style all <p>
inside <div>
div p {
color: red;
}
HTML:
<div>
<p>This is red.</p>
<section>
<p>This is also red.</p>
</section>
</div>
Example 2: Style all <a>
inside .nav
.nav a {
text-decoration: none;
}
HTML:
<nav class="nav">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
</ul>
</nav>
Child Combinator (>)
This selects all elements that are direct children of a specified element.
Example 1: Style Direct <p>
Children Inside <div>
In this example, only the <p>
elements that are direct children of the <div>
will be styled.
div > p {
color: blue;
}
HTML:
<div>
<p>This is blue.</p> <!-- Styled -->
<section>
<p>This is not blue.</p> <!-- Not Styled -->
</section>
<p>This is also blue.</p> <!-- Styled -->
</div>
Example 2: Style Direct <li>
Children Inside .menu
Here, only the <li>
elements that are direct children of an element with the class .menu
will be styled.
.menu > li {
font-weight: bold;
}
HTML:
<ul class="menu">
<li>Item 1</li> <!-- Styled -->
<li>Item 2</li> <!-- Styled -->
<ul>
<li>Sub-item 1</li> <!-- Not Styled -->
</ul>
<li>Item 3</li> <!-- Styled -->
</ul>
Example 3: Style First Direct <div>
Child Inside .container
In this example, only the first <div>
that is a direct child of .container
will be styled.
.container > div:first-child {
background-color: yellow;
}
HTML:
<div class="container">
<div>This is yellow.</div> <!-- Styled -->
<div>This is not yellow.</div> <!-- Not Styled -->
</div>
Example 4: Style Direct <a>
Children Inside .nav
Here, only the <a>
elements that are direct children of .nav
will be styled.
.nav > a {
text-decoration: none;
}
HTML:
<div class="nav">
<a href="#">Link 1</a> <!-- Styled -->
<span>
<a href="#">Link 2</a> <!-- Not Styled -->
</span>
<a href="#">Link 3</a> <!-- Styled -->
</div>
Adjacent Sibling Combinator (+)
This selects the immediate next sibling of an element.
Example 1: Style <p>
immediately following <h2>
h2 + p {
font-weight: bold;
}
HTML:
<h2>Title</h2>
<p>This is bold.</p> <!-- This will be bold -->
<p>This is not.</p>
Example 2: Style <li>
immediately following .active
li.active + li {
color: grey;
}
HTML:
<ul>
<li class="active">Active</li>
<li>Grey</li> <!-- This will be grey -->
<li>Normal</li>
</ul>
General Sibling Combinator (~)
This selects all elements that share the same parent and are siblings of a specified element.
Example 1: Style all <p>
following <h2>
h2 ~ p {
margin-left: 20px;
}
HTML:
<h2>Title</h2>
<p>Indented</p> <!-- This will be indented -->
<p>Also indented</p> <!-- This will also be indented -->
Example 2: Style all <li>
following .active
li.active ~ li {
font-size: smaller;
}
HTML:
<ul>
<li class="active">Active</li>
<li>Smaller</li> <!-- This will be smaller -->
<li>Also smaller</li> <!-- This will also be smaller -->
</ul>
When to use them
Below is short explaination about which selector comes handy on which situation.
State-based Styling: Pseudo-classes like
:hover
,:active
, and:focus
allow you to apply styles based on user interaction, without using JavaScript.Structural Styling: Pseudo-classes like
:nth-child()
,:first-child
, and:last-child
let you style elements based on their structural position within the document.Negation: The
:not()
pseudo-class allows you to exclude specific elements from being selected, offering more control over your styles.Specificity: Pseudo-classes have the same specificity as class selectors. They can be overridden by more specific selectors or inline styles.
Combining with Other Selectors: You can combine pseudo-classes with other types of selectors for more targeted styling.
Limitations and Considerations
- Pseudo-elements are not part of the DOM, so they cannot be manipulated using JavaScript.
- Not all pseudo-elements are supported by all browsers, so it's good to check compatibility.
- The
::before
and::after
pseudo-elements require thecontent
property, even if it's empty, to render.
How They Work
Cascading: If multiple selectors target the same element, the one with the highest specificity wins. Specificity is calculated based on the types of selectors used.
Inheritance: Some properties like
color
andfont-family
are inherited from parent elements if not specified.Rule Application: The browser reads the CSS from top to bottom. If two rules have the same specificity, the latter will override the former.
Importance: The
!important
flag can override specificity, but it's generally best to avoid using it unless absolutely necessary.
Specificity Hierarchy
- Inline styles have the highest specificity.
- ID selectors have higher specificity than class selectors.
- Class selectors have higher specificity than type selectors.
Example
/* Type selector */
p {
color: red;
}
/* Class selector */
.highlight {
color: green;
}
/* ID selector */
#unique {
color: blue;
}
HTML:
<p>This is red.</p>
<p class="highlight">This is green.</p>
<p id="unique">This is blue.</p>
!important
specificity
The !important
rule in CSS is used to give a particular style declaration higher importance or specificity than it would naturally have in the cascade. This can be useful for overriding styles that are otherwise difficult to change, but it should be used sparingly.
Overriding Specificity: When
!important
is added to a CSS rule, it overrides any other declarations for that property on the targeted element, regardless of specificity or source.Syntax: It is placed at the end of the declaration, before the semicolon.
p {
color: blue !important;
}Cascade Order: Even among
!important
rules, the cascade still applies. If there are conflicting!important
rules, the one that comes last in the stylesheet will be applied.Inline Styles:
!important
in an external or internal stylesheet will override inline styles on an element, which are usually the most specific.User vs. Author Styles: User stylesheets with
!important
will override author stylesheets with!important
.
Example-I: Basic Usage
/* This will make all paragraphs red, regardless of other styles */
p {
color: red !important;
}
Example-II: Overriding Inline Styles
HTML:
<p style="color: blue;">This is a paragraph.</p>
CSS:
p {
color: red !important;
}
The paragraph will be red, not blue, because of the !important
rule.
Best Practices
Use Sparingly: Overusing
!important
can make your CSS difficult to manage and debug.Specificity First: Try to use proper specificity to override styles before resorting to
!important
.Documentation: If you must use
!important
, document why it's necessary, so future developers (or future you) understand the reasoning.User Experience: Be cautious when using
!important
in a way that could disrupt user styles or accessibility features.Last Resort: Consider
!important
as a last resort, especially if you're working on large or collaborative projects where it could cause confusion or conflicts.