3. modul · CSS alapok · 14. lecke
Az előző leckében elemeket céloztunk meg. Most állapotokat fogunk: „amikor rajta az egér", „amikor ki van választva", „a harmadik elem a sorban". És a lecke végén olyan tartalmat is létrehozunk, ami nincs is benne a HTML-ben.
::before és ::after segítségével.A pszeudo-osztály olyan kijelölő, ami nem az elem fajtáját vagy a nevét nézi, hanem az állapotát vagy a helyzetét. Felismerhető a kettőspontról:
a:hover {
color: crimson;
}
Olvasva: „a elem, amikor rajta van az egér". A pszeudo szó görögül azt jelenti: „ál-". Vagyis olyan, mintha osztály lenne — csak nem te írod be a HTML-be, hanem a böngésző adja hozzá magától, amikor az adott állapot fennáll.
A HTML-ben semmit nem kell csinálnod. Nem kell osztályt írni, nem kell JavaScript. Az egér mozgásáról, a billentyűzetről, a bejelölt négyzetről és arról, hogy egy elem hányadik a sorban, a böngésző úgyis tud — a pszeudo-osztályokkal csak megkéred, hogy ezt a tudást ossza meg veled.
| Kategória | Példák |
|---|---|
| Felhasználói állapot | :hover, :focus, :active, :visited |
| Űrlap-állapot | :checked, :disabled, :required, :invalid |
| Helyzet a szülőn belül | :first-child, :last-child, :nth-child() |
| Kizárás | :not() |
A 6. leckében már említettük: egy link négyféle állapotban lehet. Most megtanuljuk mindegyiket formázni.
| Pszeudo-osztály | Mikor érvényes? |
|---|---|
:link | Még nem járt ott a felhasználó |
:visited | Már meglátogatta ezt a címet |
:hover | Rajta van az egér |
:active | Éppen le van nyomva az egérgomb |
<p> <a href="rolam.html">Vidd rám az egeret</a> </p> <p> <a href="arak.html">Vagy rám</a> </p>
a {
color: #0369a1;
text-decoration: none;
border-bottom: 2px solid #bae6fd;
padding-bottom: 2px;
}
a:hover {
color: #be123c;
border-bottom-color: #be123c;
}
a:active {
color: #f59e0b;
}
Ha mind a négy állapotot megadod, ebben a sorrendben kell írnod őket:
a:link { ... } /* L */
a:visited { ... } /* V */
a:hover { ... } /* H */
a:active { ... } /* A */
Emlékeztető: LoVe HAte — „szeretlek, utállak".
Ha a :hover szabályt a :visited elé írod,
akkor a már meglátogatott linkeken nem fog működni a hover — mert az azonos erősségű
szabályok közül a később írt nyer (15. lecke).
Biztonsági okokból a :visited esetében csak néhány tulajdonságot
állíthatsz be (főleg színeket). Ha ez nem így lenne, egy weboldal ki tudná deríteni, milyen más
oldalakon jártál. Ezért ne akarj vele méretet vagy keretet változtatni — nem fog működni.
Telefonon és tableten nincs egérmutató, tehát nincs igazi hover-állapot sem.
Ezért a :hover csak plusz lehet — soha ne rejts el mögé
olyan információt vagy gombot, ami nélkülözhetetlen.
A :focus akkor érvényes, amikor egy elem „aktív": bele
van kattintva egy mezőbe, vagy a Tab billentyűvel odanavigáltak.
<p> <label for="a">Név</label><br> <input type="text" id="a"> </p> <p> <label for="b">E-mail</label><br> <input type="email" id="b"> </p> <p><button>Küldés</button></p>
input, button {
padding: 6px 10px;
border: 2px solid #d1d5db;
border-radius: 6px;
font-size: 15px;
}
input:focus, button:focus {
outline: 3px solid #fb7185;
outline-offset: 2px;
border-color: #be123c;
background-color: #fff5f7;
}
A böngésző alapból rajzol egy fókuszkeretet. Sokan „csúnyának" tartják, és ezt teszik:
*:focus {
outline: none; /* SOHA! */
}
Ezzel használhatatlanná tetted az oldalt annak, aki billentyűzettel navigál: fogalma sem lesz, hol jár. Ha nem tetszik az alapértelmezett keret, cseréld le egy sajátra — de valami mindig legyen.
A :focus-visible csak akkor lép életbe, ha a fókusz
billentyűzetről érkezett — egérkattintásnál nem. Így a billentyűzetes
felhasználó megkapja a keretet, az egeres pedig nem lát „felesleges" díszt. Modern oldalakon
ma ez a bevett megoldás.
Az űrlapmezőknek rengeteg állapotuk van, és mindegyikhez tartozik pszeudo-osztály.
| Pszeudo-osztály | Mikor érvényes? |
|---|---|
:checked | A jelölőnégyzet vagy rádiógomb be van jelölve |
:disabled | A mező le van tiltva |
:required | Kötelezően kitöltendő |
:valid / :invalid | A beírt érték megfelel-e a szabályoknak |
:placeholder-shown | A mező üres, tehát a placeholder látszik |
<p>
<input type="checkbox" id="a">
<label for="a">Extra sajt</label>
</p>
<p>
<input type="checkbox" id="b">
<label for="b">Gomba</label>
</p>
<p>
<input type="email" placeholder="Írj be egy e-mailt"
size="24" required>
</p>
<p>
<input type="text" value="Nem szerkeszthető" disabled>
</p>
/* a bejelölt négyzet UTÁNI címke */
input:checked + label {
color: #047857;
font-weight: bold;
}
input:disabled {
background-color: #e5e7eb;
color: #9ca3af;
}
input:invalid {
border: 2px solid #be123c;
}
input:valid {
border: 2px solid #047857;
}
@ nélküli szöveget: bordó keretet kap; egészítsd ki
érvényes címmé: zöldre vált. Mindez CSS-ből, azonnal.
Az input:checked + label két dolgot köt össze, amit a 13. leckében
tanultál: egy pszeudo-osztályt és egy testvér-kijelölőt.
Olvasva: „az a label, ami közvetlenül egy bejelölt
input után áll". Így tudsz úgy formázni egy elemet, hogy közben egy
másik elem állapotát figyeled.
Ez néha zavaró: egy üres, kötelező mező már az első betű előtt hibásnak számít,
tehát rögtön pirosan jelenik meg. Éles oldalakon ezért gyakran a
:invalid:not(:placeholder-shown) kombinációt használják — így csak
akkor pirosodik, ha már elkezdték kitölteni.
Ezek a pszeudo-osztályok azt nézik, hányadik gyerek egy elem a szülőjén belül.
<ul class="lista"> <li>Első</li> <li>Második</li> <li>Harmadik</li> <li>Negyedik</li> <li>Ötödik</li> </ul>
.lista li {
padding: 4px 8px;
border-bottom: 1px solid #e5e7eb;
}
.lista li:first-child {
color: #047857;
font-weight: bold;
}
.lista li:last-child {
color: #be123c;
border-bottom: none;
}
.lista li:nth-child(3) {
background-color: #fef3c7;
}
:last-child egyik leggyakoribb haszna itt látszik: az
utolsó elemről levesszük az elválasztó vonalat, hogy ne lógjon ki egy fölösleges
csík a lista alján.
A :first-child azt jelenti: „az első gyerek, feltéve hogy
ő ilyen elem" — nem azt, hogy „az első ilyen elem". Nézd meg:
<div> <h3>Cím</h3> <p>Első bekezdés</p> </div>
Itt a p:first-child semmit nem talál, mert az első
gyerek a h3, nem a bekezdés.
Amire itt szükséged van: p:first-of-type — „az első
p a testvérei között". Ez működni fog.
Az :nth-child() zárójelébe nemcsak számot írhatsz, hanem
képletet is. Ettől lesz igazán hasznos.
| Érték | Mit jelent? |
|---|---|
3 | A harmadik elem |
even vagy 2n | Minden páros: 2., 4., 6.… |
odd vagy 2n+1 | Minden páratlan: 1., 3., 5.… |
3n | Minden harmadik: 3., 6., 9.… |
3n+1 | Az 1., 4., 7.… — minden hármas csoport eleje |
-n+3 | Az első három elem |
Az n sorban felveszi a 0, 1, 2, 3… értékeket, és
minden eredmény egy találat. A 3n+1 tehát:
3·0+1=1, 3·1+1=4, 3·2+1=7… A nullától vagy
negatív tartományba eső eredményeket a böngésző egyszerűen kihagyja.
<table> <tr><th>Név</th><th>Pont</th></tr> <tr><td>Anna</td><td>92</td></tr> <tr><td>Béla</td><td>78</td></tr> <tr><td>Cili</td><td>85</td></tr> <tr><td>Dani</td><td>64</td></tr> <tr><td>Emese</td><td>97</td></tr> </table>
table {
border-collapse: collapse;
}
td, th {
padding: 6px 14px;
text-align: left;
}
th {
background-color: #be123c;
color: white;
}
tr:nth-child(even) {
background-color: #fce7f3;
}
<ul class="sor"> <li>1</li><li>2</li><li>3</li> <li>4</li><li>5</li><li>6</li> <li>7</li><li>8</li><li>9</li> </ul>
.sor {
list-style: none;
padding: 0;
}
.sor li {
display: inline-block;
width: 32px;
padding: 8px 0;
margin: 2px;
text-align: center;
border: 1px solid #d1d5db;
}
/* minden harmadik */
.sor li:nth-child(3n) {
background-color: #be123c;
color: white;
}
/* az első három */
.sor li:nth-child(-n+3) {
border-color: #047857;
border-width: 3px;
}
3n), az
első három pedig zöld keretet kapott (-n+3).
A harmadikra mindkettő érvényes.
A :not() megfordítja a feltételt: „minden ilyen elem,
kivéve azokat, amelyek…".
<p> <button>Mentés</button> <button>Mégse</button> <button disabled>Törlés</button> </p> <ul> <li>Alma</li> <li class="kesz">Kenyér</li> <li>Tej</li> </ul>
button {
padding: 6px 14px;
border: none;
border-radius: 6px;
}
/* csak a NEM letiltott gombokra */
button:not(:disabled) {
background-color: #be123c;
color: white;
cursor: pointer;
}
/* minden li, kivéve a .kesz osztályút */
li:not(.kesz) {
font-weight: bold;
}
li.kesz {
text-decoration: line-through;
color: #9ca3af;
}
:not(:disabled) kizárta. A „Kenyér" pedig áthúzva és halványan
jelenik meg, a többi listaelem félkövéren.
li:not(:last-child) { border-bottom: 1px solid #ddd; } — minden
elem alá vonal, kivéve az utolsót. Ez elegánsabb, mint utólag levenni a vonalat
az utolsóról.
Most jön valami egészen más. A pszeudo-elem nem egy meglévő elem állapotát célozza meg, hanem új tartalmat hoz létre — olyat, ami a HTML-ben nincs is benne. Felismerhető a két kettőspontról.
| Pszeudo-elem | Hova szúr be? |
|---|---|
::before | Az elem tartalma elé |
::after | Az elem tartalma után |
content nélkül a ::before és az
::after egyáltalán nem jelenik meg — akkor sem, ha
mindenféle más tulajdonságot beállítasz rajta. Ha nincs mit beleírni, akkor is kell egy üres
érték: content: "";
<ul class="teendok"> <li class="kesz">Bevásárlás</li> <li>Takarítás</li> <li class="kesz">Mosogatás</li> </ul> <p class="kotelezo">E-mail cím</p> <p class="ar">3490</p>
.teendok {
list-style: none;
padding: 0;
}
.teendok li::before {
content: "☐ ";
color: #9ca3af;
}
.teendok li.kesz::before {
content: "☑ ";
color: #047857;
}
.kotelezo::after {
content: " *";
color: #be123c;
font-weight: bold;
}
.ar::after {
content: " Ft";
color: #7c6b74;
}
kesz osztályt, a jelölése is magától átvált.
Fontos tartalmat. A content tulajdonságban lévő szöveget a
keresők nem indexelik, másolni nem mindig lehet, és a képernyőolvasók is eltérően kezelik.
Díszítéshez, ikonokhoz, jelölésekhez kiváló — de az oldal mondanivalója maradjon a
HTML-ben.
Meglepő módon a content: "" a leggyakoribb: így hozol létre egy
üres dobozt, amit aztán színnel, mérettel és pozícióval alakítasz —
elválasztó vonalnak, díszítő négyzetnek, buborék-nyílnak. Ehhez viszont már kell a dobozmodell
(17. lecke) és a pozicionálás (19. lecke).
<p class="bevezeto">
Egyszer volt, hol nem volt, volt egyszer
egy weboldal, amelyiknek nagyon szép
volt az első betűje.
</p>
<p>
<input type="text" size="26"
placeholder="Írj ide valamit…">
</p>
.bevezeto::first-letter {
font-size: 44px;
color: #be123c;
font-weight: bold;
line-height: 1;
}
::selection {
background-color: #fbcfe8;
color: #831843;
}
::placeholder {
color: #be123c;
font-style: italic;
}
| Pszeudo-elem | Mit céloz meg? |
|---|---|
::first-letter | A bekezdés első betűjét (iniciálé) |
::first-line | Az első sort — ami ablakmérettől függ! |
::selection | Az egérrel kijelölt szövegrészt |
::placeholder | A mező súgószövegét |
::marker | A listaelem pontját vagy számát |
Egy kettőspont : | Két kettőspont :: |
|---|---|
| Pszeudo-osztály — meglévő elem állapota | Pszeudo-elem — új, nem létező elemrész |
:hover, :focus, :checked, :nth-child() |
::before, ::after, ::selection |
Régen a pszeudo-elemekhez is egy kettőspont járt (:before), és a
böngészők ma is elfogadják — visszafelé kompatibilitásból. Te írj kettőt: abból
egyből látszik, hogy pszeudo-elemről van szó, nem állapotról.
| Hiba | Mi történik, és mi a megoldás? |
|---|---|
Szóköz a kettőspont előtt: a :hover |
Ez „az a elemen belüli hoverelt elem" — nem a link maga. Néma hiba. |
| Rossz LVHA-sorrend | A meglátogatott linkeken nem működik a hover. Sorrend: :link → :visited → :hover → :active. |
outline: none a fókuszon |
A billentyűzetes felhasználó nem látja, hol jár. Cseréld le, ne vedd el. |
::before content nélkül |
Nem jelenik meg semmi. Üres esetben is kell: content: ""; |
:first-child a :first-of-type helyett |
Nem talál semmit, ha nem az adott elem az első gyerek. |
::before egy <img>-en |
Nem működik. Az üres elemeknek (img, input, br) nincs tartalmuk, amibe be lehetne szúrni. |
Fontos szöveg a content tulajdonságban |
Nem kereshető, nehezen másolható. Csak díszítés kerüljön oda. |
Csak :hover, :focus nélkül |
Aki billentyűzettel navigál, nem kap visszajelzést. Írd egybe: a:hover, a:focus { ... } |
Előbb válaszolj magadban, csak utána nézd meg a megoldást.
1. Mi a különbség az a:hover és az a :hover között?
Az első: a link maga, amikor rajta az egér. A második (szóközzel): a linken belüli elem, amikor azon van az egér. A szóköz itt is leszármazottat jelent, mint a 13. leckében.
2. Mit jelent az LVHA, és mi történik, ha felcseréled a sorrendet?
:link → :visited → :hover → :active (LoVe HAte). Ha a :hover a :visited elé kerül, akkor a már meglátogatott linkeken nem lesz hover-hatás — mert az azonos erősségű szabályok közül a később írt nyer.
3. Miért tilos az outline: none a fókuszon?
Mert aki billentyűzettel (Tab-bal) navigál, nem látja, melyik elemen áll éppen — az oldal használhatatlanná válik számára. Ha az alapértelmezett keret nem tetszik, cseréld le egy sajátra (pl. egy saját színű outline keretre), de valami jelzés mindig legyen.
4. Mely elemeket célozza meg a li:nth-child(3n+1)?
Az 1., 4., 7., 10.… elemeket. Az n felveszi a 0, 1, 2, 3… értékeket: 3·0+1=1, 3·1+1=4, 3·2+1=7 és így tovább.
5. Van egy <div>, benne egy h3, utána egy p. Miért nem hat a p:first-child szabály?
Mert a :first-child azt jelenti: „az első gyerek, ha az történetesen p". Itt viszont a h3 az első gyerek, tehát nincs találat. Helyette: p:first-of-type.
6. Beállítottál egy ::after szabályt színnel és mérettel, de semmi nem látszik. Mi hiányzik?
A content tulajdonság. Enélkül a pszeudo-elem egyáltalán nem jön létre. Ha nincs mit beleírni, akkor is kell: content: "";
7. Mikor írsz egy, és mikor két kettőspontot?
Egyet a pszeudo-osztályokhoz (állapot: :hover, :checked, :nth-child()), kettőt a pszeudo-elemekhez (új elemrész: ::before, ::after, ::selection).
8. Hogyan tennél vonalat minden listaelem alá, az utolsó kivételével?
li:not(:last-child) { border-bottom: 1px solid #ddd; } — vagy minden elemre ráteszed, majd li:last-child { border-bottom: none; }-nal leveszed. Az első elegánsabb.
:link, :visited, :hover, :active — ebben a sorrendben (LoVe HAte).:hover érintőképernyőn nem létezik — soha ne rejts mögé fontosat.:focus: a billentyűzetes navigáció alapja. Az outline tulajdonságot cseréld le, ne vedd el.:checked, :disabled, :valid, :invalid. Az input:checked + label mintával másik elemet is formázhatsz.:first-child, :last-child, :nth-child() — helyzet a szülőn belül. Vigyázat: :first-child ≠ :first-of-type.nth-child képletei: even, odd, 3n, 3n+1, -n+3 — az n 0-tól nő.:not(): kizárás. Klasszikus: li:not(:last-child).::before, ::after. A content kötelező.content tulajdonságba csak díszítés kerüljön, soha ne fontos tartalom.img, input) a ::before/::after nem működik.