CSS-mediatyypit ja mediakyselyt

Tutustutaan mediatyyppeihin ja mediakyselyihin, joilla samasta dokumentista saadaan erilainen eri ympäristöissä: kapealla ja leveällä näytöllä, tulostettuna ja käyttäjän omien asetusten mukaan.

Oppimistavoitteet

Tämän luennon jälkeen sinun pitäisi osata:

Tämä luento jatkaa CSS-luennon asioita. Erityisesti kaskadi ja mittayksiköt kannattaa olla mielessä.

1. Mediatyypit

Mediatyypillä kerrotaan, millaiselle laitteelle tyylit on tarkoitettu. Samasta dokumentista voidaan siis tehdä erinäköinen paperille kuin näytölle, ilman että sisältöä tarvitsee kirjoittaa kahteen kertaan.

1.1 Käytettävissä olevat mediatyypit

Mediatyypit, jotka selaimet tunnistavat.
TyyppiTarkoitus
allKaikki laitteet. Tämä on oletus, jos tyyppiä ei anneta
screenNäyttölaitteet
printTulostus ja tulostuksen esikatselu
Muut mediatyypit on poistettu

Vanhoissa ohjeissa luetellaan tyyppejä kuten tv, projection, handheld, braille, tty ja aural. Media Queries Level 4 on poistanut ne, eivätkä ne osu enää mihinkään. Jos kirjoitat @media handheld, sääntöjä ei sovelleta millään laitteella.

Myös speech-tyyppi on määritelty, mutta yksikään selain ei toteuta sitä. Ruudunlukija lukee sivun screen-tyyleillä, joten saavutettavuutta ei voi parantaa @media speech -säännöillä. Se tehdään oikealla HTML-rakenteella.

1.2 Mediatyypin määrittäminen

Tyylit voidaan kohdistaa kahdella tavalla. Ensimmäinen on link-elementin media-attribuutti:

<link rel="stylesheet" href="tulostus.css" media="print" />

Toinen on @media-sääntö tyylitiedoston sisällä. Tämä on nykyisin tavallisempi, koska kaikki tyylit pysyvät yhdessä tiedostossa:

@media print {
  /* tähän kaikki tulostukseen liittyvät tyylit */
}
Mediatyyppi ei vaikuta sääntöjen voimakkuuteen

Vanhoissa ohjeissa varoitetaan linkittämästä all-median tyylejä muiden jälkeen, koska ne muka "ylikirjoittaisivat" muut. Kyse ei ole mediatyypistä: mediatyyppi ei vaikuta spesifisyyteen lainkaan. Kun kaksi sääntöä osuu samaan elementtiin ja niiden spesifisyys on sama, voittaa myöhemmin kirjoitettu. Katso CSS-luennon luku 3.

Käytännön sääntö on siis sama kuin muutenkin: yleiset säännöt ensin, poikkeukset perään.

Älä anna link-elementille title-attribuuttia

title-attribuutti tekee tyylistä vaihdettavan, jolloin selain ei välttämättä ota sitä käyttöön automaattisesti. Tulostustyyleissä tämä näkyy siten, ettei tulostuksen esikatselu käytä niitä lainkaan.

2. Mediakyselyt

Mediakyselyllä (media query) tarkennetaan, millaisessa tilanteessa tyylejä käytetään. Kysely on ollut W3C:n suositus vuodesta 2012, ja se on nykyisin responsiivisen sivun perustyökalu.

Kyselyllä voi tarkastella muun muassa näyttöalueen leveyttä ja korkeutta, median suuntaa (pysty vai vaaka), kuvasuhdetta, resoluutiota sekä käyttäjän omia asetuksia. Ylivoimaisesti käytetyin on leveys.

2.1 Leveyteen perustuvat kyselyt

/* Voimassa, kun näkymäikkuna on vähintään 30em leveä */
@media (min-width: 30em) {
  /* tyylit tähän */
}

/* Voimassa, kun näkymäikkuna on enintään 30em leveä */
@media (max-width: 30em) {
  /* tyylit tähän */
}

Mediatyypin voi jättää pois, kun kysely koskee kaikkia laitteita. @media (min-width: 30em) on siis sama kuin @media all and (min-width: 30em), mutta lyhyempi ja luettavampi. Mediatyyppi kirjoitetaan vain silloin, kun sitä oikeasti tarvitaan, esimerkiksi @media print and (min-width: 20cm).

Käytä katkaisukohdissa em-yksikköä

Pikselimittainen katkaisukohta ei ota huomioon sitä, että käyttäjä on voinut suurentaa selaimensa oletusfonttikokoa. Silloin teksti kasvaa mutta asettelu ei vaihdu, ja sivu ahtautuu.

Mediakyselyssä 1em tarkoittaa aina selaimen oletusfonttikokoa, eikä siihen vaikuta se, mitä olet määritellyt html- tai body-elementille. Tavallisella asetuksella 30em on noin 480 pikseliä ja 60em noin 960 pikseliä.

2.2 Mobile first

Kyselyt voi kirjoittaa kahteen suuntaan, ja suunnalla on iso merkitys tyylitiedoston rakenteeseen.

Kaksi tapaa rakentaa responsiivinen tyylitiedosto.
Mobile first (suositus)Desktop first
Perustyyli Kapealle näytölle, ilman mediakyselyä Leveälle näytölle, ilman mediakyselyä
Kyselyt min-width: lisätään ominaisuuksia tilan kasvaessa max-width: puretaan ominaisuuksia tilan kaventuessa
Jos kysely ei toimi Käyttäjä saa yksinkertaisen mutta toimivan version Käyttäjä saa leveän version kapealle näytölle

Mobile first -tapa on suositeltavampi kahdesta syystä. Yksinkertaisin versio on turvallisin oletus, ja ominaisuuksien lisääminen on helpompaa kuin niiden purkaminen. Kapealla näytöllä kannattaa muutenkin pyrkiä yksinkertaiseen esitykseen ja sijoittaa asiat mieluummin peräkkäin kuin vierekkäin.

Älä piilota sisältöä kapealta näytöltä

Vanhoissa esimerkeissä näkee ratkaisuja kuten header { display: none; } kapealle näytölle. Puhelinkäyttäjä ei ole toisen luokan käyttäjä, eikä hänelle saa tarjota vähemmän sisältöä. Järjestä sisältö uudelleen sen sijaan, että piilotat sen.

Kapealla näytöllä on lisäksi huolehdittava siitä, ettei sivua tarvitse vierittää sivusuunnassa. Tavallisimmat syyt vaakavieritykseen ovat liian leveä kuva, taulukko tai koodilohko:

img {
  max-width: 100%;
  height: auto;
}

pre {
  overflow-x: auto;   /* vierityspalkki vain kun sitä tarvitaan */
}

2.3 Esimerkki

Muuta selainikkunan leveyttä ja katso, miten laatikon väri vaihtuu. Kokeile myös muuttaa katkaisukohtia CSS-kentässä.

2.4 Mediakyselyjen testaaminen

Kehittäjätyökaluissa on laitenäkymä, jolla sivua voi katsella eri levyisenä ilman että selainikkunaa tarvitsee raahata. Se avautuu näppäinyhdistelmällä Ctrl+Shift+M (macOS: Cmd+Shift+M) sen jälkeen, kun työkalut on avattu F12-näppäimellä. Katso HTML5-luennon luku 19.4.

Tarkista aina vähintään noin 360 pikselin leveydellä. Muista, että laitenäkymä jäljittelee vain kokoa: oikealla laitteella kannattaa kokeilla lopuksi.

3. Käyttäjän asetuksiin reagoivat kyselyt

Osa mediakyselyistä ei kysy laitteesta vaan siitä, mitä käyttäjä on käyttöjärjestelmästään valinnut. Nämä ovat helppoja toteuttaa ja parantavat saavutettavuutta selvästi.

3.1 prefers-color-scheme

Kysely kertoo, onko käyttäjä valinnut vaalean vai tumman tilan. Arvot ovat light ja dark.

/* Perustyyli on vaalea ja toimii aina. */
body {
  background-color: #ffffff;
  color: #23201c;
}

@media (prefers-color-scheme: dark) {
  body {
    background-color: #1c1a17;
    color: #f2eee7;
  }
}

Lisäksi kannattaa kertoa selaimelle, että sivu tukee molempia tiloja. Silloin myös lomakekentät, vierityspalkit ja muut selaimen omat osat mukautuvat:

:root {
  color-scheme: light dark;
}
Kontrasti on tarkistettava molemmissa tiloissa

Vaatimus 4,5:1 koskee kumpaakin tilaa erikseen. Tumman tilan yleisin virhe on täysin musta tausta ja täysin valkoinen teksti, mikä on monille epämiellyttävän kirkas. Käytä hyvin tummaa harmaata ja hieman murrettua valkoista.

3.2 prefers-reduced-motion

Osa käyttäjistä saa liikkuvasta kuvasta huimausta tai pahoinvointia, ja osalle liike vaikeuttaa keskittymistä. Käyttöjärjestelmissä on asetus, jolla liikettä pyydetään vähentämään, ja selain välittää sen tällä kyselyllä. Arvot ovat reduce ja no-preference.

Kirjoita animaatio kyselyn sisään, älä sen ulkopuolelle:

/* Oikein: liikettä ei ole oletuksena, vaan se lisätään
   vain jos käyttäjä ei ole pyytänyt sen vähentämistä. */
@media (prefers-reduced-motion: no-preference) {
  .kortti {
    transition: transform 0.3s ease;
  }
}
/* Väärin: animaatio on aina päällä, ja se poistetaan erikseen.
   Selaimessa, joka ei tue kyselyä, liike jää päälle. */
.kortti {
  transition: transform 0.3s ease;
}

@media (prefers-reduced-motion: reduce) {
  .kortti {
    transition: none;
  }
}
Sama periaate muissakin kyselyissä

Kirjoita perustyyliksi se vaihtoehto, joka on turvallisin, ja lisää muut kyselyillä. Näin sivu toimii järkevästi myös silloin, kun kyselyä ei tueta tai tyylitiedosto latautuu vain osittain.

Muita saman perheen kyselyjä ovat prefers-contrast ja forced-colors, joka kertoo Windowsin suurkontrastitilasta.

4. Tulostustyylit

Tulostettu sivu on eri media kuin näyttö. Navigointivalikkoja ei voi klikata paperilla, taustavärit kuluttavat mustetta ja linkkien osoitteet eivät näy mitenkään. Muutamalla säännöllä sivusta saa siistin tulosteen.

@media print {
  /* Piilotetaan se, mikä ei toimi paperilla */
  nav, footer, .mainos {
    display: none;
  }

  /* Näytetään linkin osoite sulkeissa linkkitekstin perässä */
  main a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.9em;
  }

  /* Vältetään sivunvaihtoa hankalissa kohdissa */
  h1, h2, h3 {
    break-after: avoid;
    break-inside: avoid;
  }

  ul, ol, dl, img, table {
    break-inside: avoid;
  }
}

4.1 Sivunvaihdon hallinta

Sivunvaihto-ominaisuudet.
OminaisuusMerkitys
break-beforeSivunvaihto ennen elementtiä
break-afterSivunvaihto elementin jälkeen
break-insideSivunvaihto elementin sisällä
Tavallisimmat arvot.
ArvoMerkitys
autoSelain päättää. Oletus
avoidVältä sivunvaihtoa tässä kohtaa
pagePakota sivunvaihto
left, rightPakota sivunvaihto niin, että seuraava sivu on vasen tai oikea
Vanhat page-break-*-ominaisuudet

Aiemmin käytettiin ominaisuuksia page-break-before, page-break-after ja page-break-inside. Ne toimivat yhä, koska selaimet muuntavat ne uusiksi, mutta uusissa tyyleissä kannattaa käyttää muotoja break-*. Huomaa myös, että vanha arvo always vastaa uutta arvoa page.

Näin testaat tulostustyylit

Avaa tulostuksen esikatselu (Ctrl+P). Kehittäjätyökaluissa voit myös pakottaa tulostusmedian: avaa komentopaletti ja etsi kohta Emulate CSS media type: print, jolloin sivu näkyy tulostustyyleillä selainikkunassa ja voit tutkia sitä normaalisti.

5. Viewport

Mobiililaitteet olettavat oletusarvoisesti, että sivu on suunniteltu leveälle näytölle. Esimerkiksi Applen laitteet olettavat sivun olevan noin 980 pikseliä leveä ja kutistavat sen näytölleen. Jos sivu on tehty responsiiviseksi, tämä arvaus vain pilaa lopputuloksen: teksti kutistuu pieneksi eivätkä mediakyselyt osu oikein.

Sen estämiseksi dokumentin head-osaan kirjoitetaan:

<meta name="viewport" content="width=device-width, initial-scale=1" />
Määrityksen osat.
OsaMerkitys
width=device-width Näkymäikkunan leveydeksi asetetaan laitteen todellinen leveys eikä kiinteää arvoa
initial-scale=1 Sivu avataan zoomaamattomana
Älä estä zoomausta

Määrityksiä user-scalable=no, maximum-scale ja minimum-scale näkee vanhoissa ohjeissa. Älä käytä niitä. Ne estävät sivun suurentamisen, mikä on suoraan saavutettavuusvaatimuksen vastaista ja tekee sivusta käyttökelvottoman heikkonäköiselle. Käytä vain kahta yllä olevaa osaa.

Yleinen kirjoitusvirhe

Kauttaviiva kuuluu attribuutin arvon ulkopuolelle. Alla oleva rivi on virheellinen, koska kauttaviiva on lainausmerkkien sisällä eikä elementtiä suljeta lainkaan:

<meta name="viewport" content="width=device-width, initial-scale=1 /">

Oikein:

<meta name="viewport" content="width=device-width, initial-scale=1" />

Jos et tee responsiivista sivua, älä käytä viewport-määritystä lainkaan. Silloin laitteen oma sovitus on parempi kuin puolivalmis responsiivisuus. Tällä kurssilla sivut tehdään responsiivisiksi, joten määritys kuuluu jokaisen sivun head-osaan.

6. Tarkistuslista

  1. Onko jokaisen sivun head-osassa oikein kirjoitettu viewport-määritys?
  2. Onko zoomaus sallittu, eli puuttuvatko user-scalable ja maximum-scale?
  3. Ovatko katkaisukohdat em-yksikössä pikselien sijaan?
  4. Onko perustyyli kirjoitettu kapealle näytölle ja lisäykset min-width-kyselyillä?
  5. Toimiiko sivu noin 360 pikselin levyisellä näytöllä ilman vaakavieritystä?
  6. Onko kaikki sisältö saatavilla myös kapealla näytöllä, eli et ole piilottanut mitään display: none -määrityksellä?
  7. Onko kontrasti riittävä sekä vaaleassa että tummassa tilassa?
  8. Onko mahdollinen liike kirjoitettu prefers-reduced-motion: no-preference -kyselyn sisään?
  9. Näyttääkö tulostuksen esikatselu järkevältä?

7. Lisätietoa

Käyttäjien kommentit

Kommentoi Lisää kommentti