033.2 Lesson 1
Certificate: |
Web Development Essentials |
---|---|
Version: |
1.0 |
Topic: |
033 CSS Content Styling |
Objective: |
033.2 CSS Selectors and Style Application |
Lesson: |
1 of 1 |
Introduction
When writing a CSS rule, we must tell the browser to which elements the rule applies. We do so by specifying a selector: a pattern that can match an element or group of elements. Selectors come in many different forms, which can be based on the element’s name, its attributes, its relative placement in the document structure, or a combination of these characteristics.
Page-Wide Styles
One of the advantages of using CSS is that you do not need to write individual rules to elements sharing the same style. An asterisk applies the rule to all elements in the web page, as shown in the following example:
* {
color: purple;
font-size: large;
}
The *
selector is not the only method to apply a style rule to all elements in the page. A selector that simply matches an element by its tag name is called a type selector, so any HTML tag name such as body
, p
, table
, em
, etc., can be used as selectors. In CSS, the parent’s style is inherited by its children elements. So, in practice, using the *
selector has the same effect as applying a rule to the body
element:
body {
color: purple;
font-size: large;
}
Furthermore, the cascading feature of CSS allows you to fine tune the inherited properties of an element. You can write a general CSS rule that applies to all elements in the page, and then write rules for specific elements or sets of elements.
If the same element matches two or more conflicting rules, the browser applies the rule from the most specific selector. Take the following CSS rules as an example:
body {
color: purple;
font-size: large;
}
li {
font-size: small;
}
The browser will apply the color: purple
and font-size: large
styles to all elements inside the body
element. However, if there are li
elements in the page, the browser will replace the font-size: large
style by the font-size: small
style, because the li
selector has a stronger relationship with the li
element than the body
selector does.
CSS does not limit the number of equivalent selectors in the same stylesheet, so you can have two or more rules using the same selector:
li {
font-size: small;
}
li {
font-size: x-small;
}
In this case, both rules are equally specific to the li
element. The browser cannot apply conflicting rules, so it will choose the rule that comes later in the CSS file. To avoid confusion, the recommendation is to group together all properties that use the same selector.
The order in which the rules appear in the stylesheet affect how they are applied in the document, but you can override this behavior by using an important
rule. If, for any reason, you want to keep the two separate li
rules, but force the application of the first one instead of the second one, mark the first rule as important:
li {
font-size: small !important;
}
li {
font-size: x-small;
}
Rules marked with !important
should be used with caution, because they break the natural stylesheet cascading and make it harder to find and correct problems within the CSS file.
Restrictive Selectors
We saw that we can change certain inherited properties by using selectors matching specific tags. However, we usually need to use distinct styles for elements of the same type.
Attributes of HTML tags can be incorporated into selectors to restrict the set of elements they refer to. Suppose the HTML page you are working on has two types of unordered lists (<ul>
): one is used at the top of the page as a menu to the sections of the website and the other type is used for conventional lists in the text body:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSS Basics</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/articles">Articles</a></li>
<li><a href="/about">About</a></li>
</ul>
<div id="content">
<p>The three rocky planets of the solar system are:</p>
<ul>
<li>Mercury</li>
<li>Venus</li>
<li>Earth</li>
<li>Mars</li>
</ul>
<p>The outer giant planets made most of gas are:</p>
<ul>
<li>Jupiter</li>
<li>Saturn</li>
<li>Uranus</li>
<li>Neptune</li>
</ul>
</div><!-- #content -->
<div id="footer">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/articles">Articles</a></li>
<li><a href="/about">About</a></li>
</ul>
</div><!-- #footer -->
</body>
</html>
By default, each list item has a black circle to its left. You may want to remove the circles from the top menu list while leaving the circles in the other list. However, you cannot simply use the li
selector because doing so will also remove the circles in the list inside the text body section. You will need a way to tell the browser to modify only the list items used in one list, but not the other.
There are several ways to write selectors matching specific elements in the page. As mentioned earlier, we will first see how to use the elements' attributes to do so. For this example in particular, we can use the id
attribute to specify the top list only.
The id
attribute assigns a unique identifier to the corresponding element, which we can use as the selector part of the CSS rule. Before writing the CSS rule, edit the sample HTML file and add id="topmenu"
to the ul
element used for the top menu:
<ul id="topmenu">
<li>Home</li>
<li>Articles</li>
<li>About</li>
</ul>
There is already a link
element in the head
section of the HTML document pointing to the style.css
stylesheet file in the same folder, so we can add the following CSS rules to it:
ul#topmenu {
list-style-type: none
}
The hash character is used in a selector, following an element, to designate an ID (without spaces separating them). The tag name to the left of the hash is optional, as there will be no other element with the same ID. Therefore, the selector could be written just as #topmenu
.
Even though the list-style-type
property is not a direct property of the ul
element, CSS properties of the parent element are inherited by its children, so the style assigned to the ul
element will be inherited by its child li
elements.
Not all elements have an ID by which they can be selected. Indeed, only a few key layout elements in a page are expected to have IDs. Take the lists of planets used in the sample code, for instance. Although it is possible to assign unique IDs for each individual repeated element like these, this method is not practical for longer pages with lots of contents. Rather, we can use the parent div
element’s ID as the selector to change the properties of its inner elements.
However, the div
element is not directly related to HTML lists, so adding the list-style-type
property to it will have no effect on its children. Thus, to change the black circle in the lists inside the content div
to a hollow circle, we should use a descendant selector:
#topmenu {
list-style-type: none
}
#content ul {
list-style-type: circle
}
The #content ul
selector is called a descendant selector because it matches only the ul
elements that are children of the element whose ID is content
. We can use as many levels of descendance as necessary. For instance, using #content ul li
would match only the li
elements that are descendants of ul
elements that are descendants of the element whose ID is content
. But in this example, the longer selector will have the same effect as using #content ul
, because the li
elements inherit the CSS properties set to their parent ul
. Descendant selectors are an essential technique as the page layout grows in complexity.
Let’s say that now you want to change the font-style
property of the list items in the topmenu
list and in the list in the footer div to make them look oblique. You can’t simply write a CSS rule using ul
as the selector, because it will also change the list items in the content div. So far, we have changed CSS properties using one selector at a time, and this method can also be used for this task:
#topmenu {
font-style: oblique
}
#footer ul {
font-style: oblique
}
Separate selectors are not the only way to do it, though. CSS allow us to group together selectors that share one or more styles, using a list of selectors separated by commas:
#topmenu, #footer ul {
font-style: oblique
}
Grouping selectors eliminates the extra work of writing duplicate styles. Furthermore, you may want to change the property again in the future and may not remember to change it in all the different places.
Classes
If you do not want to worry too much about the element hierarchy, you can simply add a class
to the set of elements you want to customize. Classes are similar to IDs, but instead of identifying only a single element in the page, they can identify a group of elements sharing the same characteristics.
Take the sample HTML page we are working on, for instance. It’s unlikely that in real-world pages we will find structures simple as that, so it would be more practical to select an element using classes only, or a combination of classes and descendancy. To apply the font-style: oblique
property to the menu lists using classes, first we need to add the class
property to the elements in the HTML file. We’ll do it first in the top menu:
<ul id="topmenu" class="menu">
<li><a href="/">Home</a></li>
<li><a href="/articles">Articles</a></li>
<li><a href="/about">About</a></li>
</ul>
And then in the footer’s menu:
<div id="footer">
<ul class="menu">
<li><a href="/">Home</a></li>
<li><a href="/articles">Articles</a></li>
<li><a href="/about">About</a></li>
</ul>
</div><!-- #footer -->
With that, we can replace the selector group #topmenu, #footer ul
by the class-based selector .menu
:
.menu {
font-style: oblique
}
As with the ID-based selectors, adding the tag name to the left of the dot in class-based selectors is optional. However, unlike IDs, the same class is supposed to be used in more than one element and they do not even need to be of the same type. Therefore, if the menu
class is shared among different element types, using the ul.menu
selector would match only the ul
elements having the menu
class. Instead, using .menu
as the selector will match any element having the menu
class, regardless of its type.
Furthermore, elements can be associated to more than one class. We could differentiate between the top and the bottom menu by adding an extra class to each one of them:
<ul id="topmenu" class="menu top">
And in the footer’s menu:
<ul class="menu footer">
When the class
attribute has more than one class, they must be separated by spaces. Now, in addition to the CSS rule shared between elements of the menu
class, we can address the top and footer menu using their corresponding classes:
.menu {
font-style: oblique
}
.menu.top {
font-size: large
}
.menu.footer {
font-size: small
}
Be aware that writing .menu.top
differs from .menu .top
(with a space between the words). The first selector will match elements that have both menu
and top
classes, whereas the second will match elements that have the top
class and a parent element with the menu
class.
Special Selectors
CSS selectors can also match dynamic states of elements. These selectors are particularly useful for interactive elements, such as hyperlinks. You may want the appearance of hyperlinks when the mouse pointer moves over them, to draw the visitor’s attention.
Back to our sample page, we could remove the underlines from the links in the top menu and show a line only when the mouse pointer moves over the corresponding link. To do this, we first write a rule to remove the underline from the links in the top menu:
.menu.top a {
text-decoration: none
}
Then we use the :hover
pseudo-class on those same elements to create a CSS rule that will apply only when the mouse pointer is over the corresponding element:
.menu.top a:hover {
text-decoration: underline
}
The :hover
pseudo-class selector accepts all the CSS properties of conventional CSS rules. Other pseudo-classes include :visited
, which matches hyperlinks that have already been visited, and :focus
, which matches form elements that have received focus.
Guided Exercises
-
Suppose an HTML page has a stylesheet associated to it, containing the two following rules:
p { color: green; } p { color: red; }
What color will the browser apply to the text inside the
p
elements? -
What is the difference between using the ID selector
div#main
and#main
? -
Which selector matches all
p
elements used inside adiv
with ID attribute#main
? -
What is the difference between using the class selector
p.highlight
and.highlight
?
Explorational Exercises
-
Write a single CSS rule that changes the
font-style
property tooblique
. The rule must match onlya
elements that are inside<div id="sidebar"></div>
or<ul class="links"></ul>
. -
Suppose you want to change the style of the elements whose
class
attribute is set toarticle reference
, as in<p class="article reference">
. However, the.article .reference
selector does not appear to alter their appearance. Why is the selector not matching the elements as expected? -
Write a CSS rule to change the
color
property of all visited links in the page tored
.
Summary
This lesson covers how to use CSS selectors and how the browser decides what styles to apply to each element. Being separate from the HTML markup, CSS provides many selectors to match individual elements or groups of elements in the page. The lesson goes through the following concepts and procedures:
-
Page wide styles and style inheritance.
-
Styling elements by type.
-
Using the element ID and class as the selector.
-
Compound selectors.
-
Using pseudo-classes to style elements dynamically.
Answers to Guided Exercises
-
Suppose an HTML page has a stylesheet associated to it, containing the two following rules:
p { color: green; } p { color: red; }
What color will the browser apply to the text inside the
p
elements?The color
red
. When two or more equivalent selectors have conflicting properties, the browser will choose the last one. -
What is the difference between using the ID selector
div#main
and#main
?The selector
div#main
matches adiv
element having the IDmain
, whereas the#main
selector matches the element having the IDmain
, regardless of its type. -
Which selector matches all
p
elements used inside adiv
with ID attribute#main
?The selector
#main p
ordiv#main p
. -
What is the difference between using the class selector
p.highlight
and.highlight
?The selector
p.highlight
matches only the elements of typep
having the classhighlight
, whereas the.highlight
selector matches all elements having the classhighlight
, regardless of their type.
Answers to Explorational Exercises
-
Write a single CSS rule that changes the
font-style
property tooblique
. The rule must match onlya
elements that are inside<div id="sidebar"></div>
or<ul class="links"></ul>
.#sidebar a, ul.links a { font-style: oblique }
-
Suppose you want to change the style of the elements whose
class
attribute is set toarticle reference
, as in<p class="article reference">
. However, the.article .reference
selector does not appear to alter their appearance. Why is the selector not matching the elements as expected?The
.article .reference
selector will match the elements having the classreference
that are descendants of elements having the classarticle
. To match elements having botharticle
andreference
classes, the selector should be.article.reference
(without the space between them). -
Write a CSS rule to change the
color
property of all visited links in the page tored
.a:visited { color: red; }