CSS Tutorial / Basic CSS Selectors: Type, Class, ID, and Attributes
CSS selectors identify the HTML elements to which a rule applies. Type selectors match tag names, class selectors match reusable labels, ID selectors match an identifier, and attribute selectors match attributes or their values.
Compare selectors against the same HTML
Let's read the selector based on the following four items: A and B are p and have a notice class, and B also has an urgent class. C is a classless p, D is a div with a notice class. English letters A~D are only marks to distinguish objects in the description and are not CSS syntax.
<p id="opening" class="notice" data-tags="garden visit">A: Operating hours</p> <p class="notice urgent">B: Rainy weather notice</p> <p>C: What you need</p> <div class="notice">D: Information box</div>
| selector | What to choose | Judgment criteria |
|---|---|---|
p |
A, B, C | tag name is p |
.notice |
A, B, D | Notice class included |
p.notice |
A, B | p and includes notice class |
.notice.urgent |
B | Includes both notice and urgent classes |
#opening |
A | ID is opening |
[data-tags~="visit"] |
A | Includes the word visit among attribute values separated by spaces |
When reading a selector, make sure the condition is on the element itself that the CSS will be applied to. The two conditions in p.notice refer to the same element. On the other hand, the space in p .notice means to find another element in p. Rules that change the target depending on the space can be found along with the structure in the CSS Combinators and Pseudo-Classes.
Use type and universal selectors
p { color: #333; }
* { box-sizing: border-box; }
p picks all p elements. It is simple to decorate the same tag in common, but to decorate the notice and body paragraphs separately, additional conditions such as class are required. The universal selector * is a notation that selects all elements. It does not automatically include pseudo-elements.
Here, box-sizing: border-box is an auxiliary setting that calculates including the padding and border when specifying the width and height. You can do this exercise even if you haven't yet learned the ins and outs of size calculations. Using a universal selector does not mean you have to change all text colors and backgrounds at once. Think about the design of common settings and specific elements.
Select classes and IDs
.notice { background-color: #e9f7ef; }
p.notice { border-left: 4px solid #087f5b; }
.notice.urgent { font-weight: bold; }
#opening { color: #087f5b; }
A class can be reused for multiple elements. class="notice urgent" in HTML is a list of two class names with spaces, not a single name notice urgent . In CSS, add a dot in front to select .notice or .urgent. .notice.urgent only applies to elements with both names.
An ID must be unique within one HTML document. Do not give ten notices the same id="opening". Use classes for reusable styling and IDs for unique identification or fragment destinations. ID selectors have higher specificity than class selectors, but specificity is compared within the applicable origin, importance, and layer conditions; adding IDs indiscriminately makes conflicts harder to maintain. For further detail, see CSS Inheritance, Specificity, and the Cascade.
In the example, we color by ID to show differences across subjects. If you actually need the same green color for multiple notices, you can simplify it by adding the color to the .notice rule. The goal is not to use universal selector types, but to pick only the range you need.
Match attributes and their values
input[required] { border: 2px solid #087f5b; }
input[type="email"] { background-color: #fff4cc; }
[data-tags~="visit"] { outline: 1px dashed #777; }
a[href^="https://"] { color: #1d4ed8; }
| notation | meaning | Applying it to the example |
|---|---|---|
[required] |
Element with required attribute | Distinguish between required input fields. Even if the value is an empty string, it will match if the property is present. |
[type="email"] |
The type value is exactly email | Select the email input field. |
[data-tags~="visit"] |
Include the word visit in space-separated values | It matches garden visit, but does not match revisit. |
[href^="https://"] |
href string starts with https:// | Select the link with that string. It is not an external site identification function itself. |
An https:// address can point to the same site, so that prefix does not identify external links by itself. Likewise, [data-tags="visit"] matches the entire attribute value and does not match garden visit. Use the appropriate comparison operator for the intended condition. See MDN: Attribute selectors.
Run the complete selector example
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Small Garden</title>
<style>
* { box-sizing: border-box; }
body { margin: 24px; font-family: sans-serif; line-height: 1.7; }
p { color: #333; }
.notice { background-color: #e9f7ef; padding: 12px; }
p.notice { border-left: 4px solid #087f5b; }
.notice.urgent { font-weight: bold; }
#opening { color: #087f5b; }
[data-tags~="visit"] { outline: 1px dashed #777; }
a[href^="https://"] { color: #1d4ed8; }
input[required] { border: 2px solid #087f5b; }
input[type="email"] { background-color: #fff4cc; }
</style>
</head>
<body>
<h1>Small Garden</h1>
<p id="opening" class="notice" data-tags="garden visit">A: We open at 9am every day.</p>
<p class="notice urgent">B: In case of rain, the outdoor program will be canceled.</p>
<p>C: Bring a water bottle and comfortable shoes.</p>
<div class="notice">D: This is an information box.</div>
<p><a href="https://example.com/">E: External guidance link</a></p>
<form>
<label for="email">Email (required)</label>
<input id="email" type="email" name="email" required>
<button type="submit">Request information</button>
</form>
</body>
</html>
If you save and open with index.html, A·B·D will have a light background and 12px padding, and only A·B corresponding to p.notice will have a left border. B has both classes and looks bold. A is the ID and is colored green, and a dotted outline is also created due to the visit attribute value. C remains a regular paragraph.
The border of the email input field becomes thick under the required condition, and the background becomes yellow under the type condition. The actual input validation function of required is handled by the HTML attribute, and CSS only changes the appearance of the input box. The external link address in the example is for illustrative purposes only. Please do not use this as a guide link to the actual service. The way to select the existence of an attribute is different from the way to select the verification result. CSS Form States: Focus, Validation, disabled, and readonly compares required and error state selectors together.
Change conditions and predict the result
- Try changing
p.noticeto.noticeto widen the target of the left border. The expected result is that the border that originally existed only in A·B also appears in D. After confirmation, revert back to the original selector. - Change the class of B to
class="urgent". B is still p, but it loses the notice condition, so the guide background, left border, and bold text for.notice.urgentdisappear. Complex selectors do not match just because of the urgent class. - Change the data-tags value of A to
garden revisit. Since there is no independent word visit, the dotted outline should disappear. Make sure you don't confuse visit and revisit as substrings.
For each exercise, save the file and then refresh to check and return to the original values. If only the expected object does not change, compare the actual class·id·property name first. You can distinguish between selection errors and priority conflicts by looking in the developer tools to see if the rules match the selected elements.










