Å mestre nettoppsett uten å mestre CSS er omtrent like gjennomførbart som å lære å svømme på tørt land. Men i motsetning til svømming - som en gang er mestret, er en ferdighet som forblir hos deg hele livet - å mestre CSS er en prosess som aldri ender, siden CSS selv utvikler seg kontinuerlig.
Utfordringen forverres av forskjeller i CSS-implementering og -støtte på tvers av forskjellige nettlesere (og til og med på tvers av forskjellige versjoner av samme nettleser), så vel som forskjellige bruksområder for CSS-anbefalinger. I godt over et tiår har webdesignere og utviklere slitt med sporadiske og inkonsekvente utbrudd av tillegg CSS3-funksjoner støttes i hver nye nettleserversjon.
Men vær som den måtte, mestring av CSS er en absolutt nødvendighet for ethvert fast stoff webdesigner eller utvikler . Denne artikkelen vil lede deg gjennom noen grunnleggende CSS-layoutprinsipper, fra klassiske CSS2-teknikker til de nyeste layouttilnærmingene i CSS3.
MERK: Alle kodeeksempler i denne artikkelen bruker HTML5 elementer og Sass syntaks. Full arbeidskode kan klones fra https://github.com/laureanoarcanio/css-layout-examples .
En av de beste måtene å lære seg en teknologi på er å ha en spesifikk brukssak du prøver å støtte eller et bestemt problem du prøver å løse. Mot det formål vil vi fokusere på en brukstilfelle med et spesifikt sett med krav.
Brukssaken vår består av en Web App-layout med en viss dynamisk oppførsel. Det vil ha faste elementer på siden, for eksempel en topptekst, bunntekst, navigasjonsmeny og undernavigasjon, samt en rullebar innholdsseksjon. Her er de spesifikke layoutkravene:
For det første, her er HTML5-markeringen vi vil bruke med eksempelimplementeringen vår ved hjelp av klassisk CSS:
z-index
I CSS2 kan vi oppnå de faste elementene på siden (topptekst, bunntekst osv.) Ved å benytte en posisjonert layoutmodell som bruker fast posisjonering.
I tillegg bruker vi z-index
CSS-egenskap for å sikre at de faste elementene våre forblir 'på toppen av' det andre innholdet på siden. z-index
egenskap spesifiserer stabelrekkefølgen til et element, der et element med større stabelrekkefølge alltid er 'på toppen av' et element med lavere stabelrekkefølge. Merk at z-index
eiendommen fungerer bare med plassert elementer. Som eksempel bruker vi vilkårlig width
verdi på 20 (som er høyere enn standard) for å sikre at våre faste elementer forblir visuelt i forkant.
Vi setter også inn #header, #footer { position: fixed; width: 100%; z-index: 20; } #header { top: 0; height: 5em; } #footer { bottom: 0; height: 3em; }
eiendom til 100% som instruerer nettleseren om å bruke all tilgjengelig plass horisontalt for elementet.
#nav
OK, så det er topptekst og bunntekst. Men hva med #subnav
og #nav
?
For #subnav
og top
, bruker vi en litt mer sofistikert teknikk kjent som CSS-utvidelse , som kan brukes når posisjonering av elementer som fikset (dvs. på en fast posisjon på siden) eller som absolutt (dvs. på en spesifisert posisjon i forhold til den nærmeste plassert forfedre eller til den inneholder blokken).
Vertikal utvidelse oppnås ved å stille inn begge bottom
og left
egenskaper til et element til en fast verdi, slik at elementet utvides vertikalt for å bruke det gjenværende vertikale rommet tilsvarende. I utgangspunktet er det å knytte toppen av elementet til en bestemt avstand fra toppen av siden og bunnen av elementet til en bestemt avstand fra bunnen av siden, slik at elementet utvides for å fylle hele det vertikale rommet mellom de to punktene.
Tilsvarende oppnås horisontal ekspansjon ved å sette begge right
og #nav, #subnav { position: fixed; top: 6em; /* leave 1em margin below header */ bottom: 4em; /* leave 1em margin above footer */ z-index: 20; } #nav { left: 0; width: 5em; } #subnav { left: 6em; /* leave 1em margin to right of nav */ width: 13em; }
egenskaper til et element til en fast verdi, slik at elementet utvides horisontalt for å bruke det gjenværende horisontale rommet tilsvarende.
For vårt brukstilfelle må vi bruke vertikal ekspansjon.
margin
Det viktigste rullebare innholdsområdet kan bare stole på standardposisjon (statisk), hvor elementene gjengis i rekkefølge slik de vises i dokumentflyten. Siden alt annet på siden vår er i en fast posisjon, er dette elementet det eneste som er i dokumentflyten. Som et resultat er alt vi trenger å gjøre for å plassere den riktig, å spesifisere dens #main { margin: 6em 0 4em 20em; }
eiendom for å unngå overlapping med den faste toppteksten, bunnteksten og nav / subnav:
5em
Og med det har vi oppfylt de grunnleggende layoutkravene for brukssaken vår ved hjelp av CSS2, men vi må fortsatt tilfredsstille tilleggskravene til dynamisk funksjonalitet.
Kravene uttalte at vår navigasjonsmeny som standard bare viser ikoner, men at den også kan utvides til å vise tekst (og deretter kan skjules for å vise bare ikoner igjen).
La oss starte med å bare legge til #nav { left: 0; width: 5em; &.expanded { /* Sass notation */ width: 10em; } }
til bredden på navigasjonsmenyen når den utvides. Vi gjør dette ved å lage en 'utvidet' CSS-klasse som vi dynamisk kan legge til eller fjerne fra navigasjonsmenyelementet:
$('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav’').toggleClass('expanded'); });
Her er et eksempel på JavaScript-koden (i dette eksemplet bruker vi jQuery) som kan brukes til å veksle navigasjonsmenyen mellom utvidet og skjult modus dynamisk, basert på at brukeren klikker på nav-vekselikonet:
#subnav { left: 6em; width: 13em; &.expanded { left: 11em; /* move it on over */ } } #main { margin: 6em 0 4em 20; z-index: 10; &.expanded { margin-left: 25em; /* move it on over */ } }
Og med det kan nav-menyen vår nå utvides eller skjules dynamisk. Flott.
Vel, ganske bra, men ikke helt. Selv om nav-menyen nå kan utvides og trekkes sammen, spiller den ikke bra med resten av siden. Den utvidede nav-menyen overlapper nå subnav som definitivt ikke er ønsket oppførsel.
Dette avslører en av nøkkelbegrensningene til CSS2; nemlig det er vei for mye som må hardkodes med faste posisjonsverdier. Som et resultat, for de andre elementene på siden som må plasseres på nytt for å imøtekomme den utvidede navmenyen, må vi definere ytterligere 'Utvidede' CSS-klasser med enda mer faste posisjonsverdier.
$('.layout-classic #nav').on('click', 'li.nav-toggle', function() { $('#nav, #subnav, #main').toggleClass('expanded'); });
Vi må da utvide JavaScript-koden vår for å legge til dynamisk justering av disse andre elementene også når nav-bryteren er klikket av brukeren:
display: none
OK, det fungerer bedre.
La oss nå ta opp kravet om å ha noen sider som skjuler undermenyen. Spesielt vil vi at undermenyen skal skjules når brukeren klikker på 'brukere' -ikonet i hovednavneområdet.
Så først lager vi en ny klasse 'skjult' som gjelder .hidden { display: none; }
:
#subnav
Og igjen, vi bruker JavaScript (jQuery) til å bruke den 'skjulte' CSS-klassen på $('#nav.fa-user').on('click', function() { $('#subnav').toggleClass('hidden'); });
element når brukeren klikker på brukerikonet:
#subnav
Med dette tillegget, #subnav
elementet blir riktig skjult når brukeren klikker på 'brukere' -ikonet, men plassen den hadde okkupert forblir ubrukt , i stedet for at de andre elementene utvider seg til å bruke plassen som er forlatt av #subnav
element.
For å få ønsket oppførsel når vi skjuler main
vil vi benytte en av de mindre kjente, men likevel svært nyttige, CSS-velgerne kjent som tilstøtende søskenvelger .
De tilstøtende søskenvelger lar deg spesifisere to elementer, bare velge de forekomster av det andre elementet som umiddelbart følger det angitte første elementet.
Følgende vil for eksempel bare velge elementene med ID subnav
at umiddelbart følg et element med ID #subnav + #main { margin-left: 20em; }
:
#main
Ovennevnte CSS-kodebit angir venstre margin på 20em
til #subnav
hvis og bare hvis den følger umiddelbart en vist #nav
.
Imidlertid, hvis expanded
utvides (som fører til at #main
klassen også blir lagt til #main
, basert på vår tidligere kode), flytter vi venstre marg på #subnav + #main.expanded { margin-left: 25em; }
til 25em.
#subnav
Og hvis #main
er skjult, flytter vi venstre marg på #nav
helt til 6 em for å være rett ved siden av #subnav.hidden + #main { margin-left: 6em; }
:
#subnav
(Merk: En ulempe ved å bruke den tilstøtende søskenvelgeren er at den tvinger oss til å alltid ha #subnav
til stede i DOM, uavhengig av om den vises.)
Til slutt, hvis #nav
er skjult og #main
utvides, setter vi venstre marg på 11em
kl #subnav.hidden + #main.expanded { margin-left: 11em; }
:
calc()
Dette gjør at vi kan koble sammen ting uten tung JavaScript-kode, men vi kan også se hvor komplisert denne koden kan bli hvis vi legger til flere elementer på siden. Vi ser igjen at med CSS2, masse hardkoding av posisjonsverdier er nødvendig for å få ting til å fungere skikkelig.
CSS3 tilbyr betydelig forbedret funksjonalitet og layoutteknikker som gjør det mye enklere å bruke og mye mindre avhengig av hardkodede verdier. CSS3 er iboende designet for å støtte mer dynamisk oppførsel og er i så måte mer “programmerbar”. La oss undersøke noen av disse nye mulighetene når det gjelder brukssaken vår.
calc()
FunksjonDen nye CSS3 calc()
funksjon kan brukes til å beregne CSS-eiendomsverdier dynamisk (merk imidlertid det støtten varierer på tvers av nettlesere). Uttrykket gitt til +
funksjon kan være et hvilket som helst enkelt uttrykk som kombinerer de grunnleggende aritmetiske operatorene (-
, *
, /
, calc()
) ved å bruke standardoperatørprioritetsregler.
Bruk av #nav, #subnav { position: fixed; height: calc(100% - 10em); /* replaces */ z-index: 20; }
funksjonen kan bidra til å unngå mye hardkoding av verdier som kreves av CSS2. I vårt tilfelle gjør dette oss i stand til å oppnå CSS-utvidelse mer dynamisk. For eksempel:
height
Med ovenstående calc()
spesifikasjon ved hjelp av top:6em
funksjon, oppnår vi det samme resultatet som vi gjorde i CSS2 med bottom:4em
og top
, men på en mye mer fleksibel og adaptiv måte, og uten å måtte kode hardt bottom
og display
posisjonsverdier.
Flexbox er et nytt oppsett introdusert i CSS3 ( support varierer mellom nettlesere ). Flexbox-oppsettet gjør det enklere å ordne elementer på en side på en måte som oppfører seg forutsigbart på tvers av forskjellige skjermstørrelser, oppløsninger og enheter. Det er derfor spesielt nyttig i sammenheng med Responsivt webdesign .
Viktige funksjoner inkluderer:
Flexbox introduserer sitt eget unike sett med vilkår og konsepter. Noen av disse inkluderer:
flex
eiendom satt til inline-flex
eller flex-directio
som fungerer som beholderelement for fleksible gjenstander.flex-wrap
n som betegner hovedaksen langs som flex-elementene er lagt ut. De kryssakse er da aksen vinkelrett på hovedaksen.main size
eiendom.cross size
og .layout-flexbox { display: flex; flex-direction: column; }
, som spesifiserer størrelsen på henholdsvis hovedaksen og tverraksen til fleksbeholderen.OK, så med den korte introen, her er den alternative markeringen vi kan bruke hvis vi bruker en flexbox-layout:
content-area
For vårt eksempel på bruk er hovedoppsettet (topptekst, innhold, bunntekst) vertikalt, så vi setter fleksboksen vår til å bruke en kolonneoppsett:
#nav
Selv om hovedoppsettet vårt er vertikalt, er elementene i innholdsområdet vårt (nav, subnav, main) lagt ut horisontalt. Hver flexcontainer kan bare definere en retning (dvs. layoutet må enten være vannrett eller loddrett). Derfor, når oppsettet krever mer enn dette (et vanlig tilfelle for en appoppsett), kan vi hekke flere containere hver i hverandre, hver med forskjellige retningsoppsett.
Derfor har vi lagt til en ekstra beholder (som jeg har kalt #subnav
) innpakning #main
, flex
og flex: ;
. På denne måten kan den generelle utformingen være vertikal, mens innholdsområdets innhold kan legges horisontalt.
Nå for å plassere våre fleksible varer, skal vi bruke eiendommen flex-grow
det er en stenografi for flex-shrink
. Disse tre fleksibilitetsegenskapene er de som bestemmer hvordan flexartiklene våre fordeler noe ledig plass som er igjen mellom dem i strømningsretningen, som følger:
Innstilling #header { flex: 0 0 5em; } #footer { flex: 0 0 3em; }
og flex-grow
begge til null betyr at størrelsen på varen er fikset og det vil ikke vokse eller krympe for å imøtekomme at det er mer eller mindre ledig plass tilgjengelig. Dette er hva vi gjør for topptekst og bunntekst siden de har en fast størrelse:
flex-shrink
For å få en vare til å ta all ledig ledig plass, angir du flex-basis
og auto
verdier både til 1 og sett dens content-area
verdi til display: flex
. Dette er hva vi gjør for innholdsområdet siden vi vil at det skal ta opp all ledig ledig plass.
Og som vi sa tidligere, vil vi ha varene inni flex-direction: row;
å legge ut i radretning, så vi legger til #nav
; og #subnav
. Dette gjør innholdsområdet til en ny flexcontainer for content-area
, .content-area { display: flex; flex-direction: row; flex: 1 1 auto; /* take up all available space */ margin: 1em 0; min-height: 0; /* fixes FF issue with minimum height */ }
og `#main.
Så det er det vi ender opp med for CSS for #nav
:
#subnav
I innholdsområdet, begge flex
og #nav { flex: 0 0 5em; margin-right: 1em; overflow-y: auto; } #subnav { flex: 0 0 13em; overflow-y: auto; margin-right: 1em; }
har faste størrelser, så vi setter bare overflow-y: hidden
eiendommen tilsvarende:
#main
(Vær oppmerksom på at jeg har lagt til #main { flex: 1 1 auto; overflow-y: auto; }
i disse CSS-spesifikasjonene for å overvinne innhold som overstiger containerens høyde. Chrome trenger faktisk ikke dette, men FireFox gjør det.)
layout-flexbox
tar opp resten av ledig plass:
layout-classic
Alt dette ser bra ut, så la oss nå legge til den dynamiske oppførselen vår og se hvordan det går.
JavaScript er identisk med det vi hadde før (bortsett fra her, CSS-elementbeholderklassen vi spesifiserer er $('.layout-flexbox #nav’).on('click', 'li.nav-toggle', function() { $('#nav').toggleClass('expanded'); });
mens før den var expanded
):
#nav { flex: 0 0 5em; /* collapsed size */ margin-right: 1em; overflow-y: auto; &.expanded { flex: 0 0 10em; /* expanded size */ } }
Vi legger til display
klasse til CSS som følger:
fr
Og voila!
Vær oppmerksom på at vi ikke trenger å fortelle andre gjenstander om breddeendringen denne gangen, siden flexbox-oppsettet håndterer alt dette for oss.
Det eneste som er igjen da er å skjule subnav. Og gjett hva? Det 'fungerer bare' også uten ytterligere endringer ved å bruke den samme JavaScript-koden som før. Flexbox vet om ledig plass, og det gjør at layoutet vårt fungerer uten ekstra kode. Ganske kult.
Flexbox gir også noen interessante måter å sentrere både vertikale og horisontale elementer på. Vi innser her hvor viktig det er for et presentasjonsspråk å inkludere forestillingen om ledig plass og hvor skalerbar koden vår kan bli ved hjelp av denne typen teknikker. På den annen side kan begrepene og notasjonen her ta litt mer å mestre enn klassisk CSS.
Hvis Flexbox Layout er i forkant av CSS3, kan det være sikt at Grid Layout er i blødningskanten. W3C-spesifikasjonen er fremdeles i utkaststilstand, og den har den fortsatt ganske begrenset nettleserstøtte . (Den er aktivert i Chrome gjennom 'eksperimentelle funksjoner på nettplattformen' i krom: // flagg ).
Når det er sagt, anser jeg personlig ikke dette utkastet som revolusjonerende. Snarere, som HTML5 design prinsipper stat: 'Når en praksis allerede er utbredt blant forfattere, bør du vurdere å vedta den i stedet for å forby den eller finne på noe nytt.'
Følgelig har markeringsbaserte rutenett blitt brukt i lang tid, så nå følger CSS Grid Layout bare det samme paradigmet, og tilbyr alle fordelene og mye mer i presentasjonslaget uten krav til markering.
Den generelle ideen er å ha en forhåndsdefinert, fast eller fleksibel rutenettoppsett der vi kan plassere elementene våre. I likhet med flexbox fungerer den også på fri plass-prinsippet og lar oss definere både vertikale og horisontale 'retninger' i samme element, noe som gir fordeler i kodestørrelse og fleksibilitet.
Rutenettoppsett introduserer to typer nett; nemlig eksplisitt og implisitt . For enkelhets skyld vil vi fokusere på eksplisitte rutenett i dette.
I likhet med flexbox introduserer Grid layout sitt eget unike sett med vilkår og konsepter. Noen av disse inkluderer:
.layout-grid { display: grid; grid-template-columns: auto 0 auto 1em 1fr; grid-template-rows: 5em 1em 1fr 1em 3em; }
egenskap satt til 'rutenett' eller 'inline-rutenett' der de inneholdte elementene er lagt ut ved å posisjonere og justere til et forhåndsdefinert rutenett (eksplisitt modus). Rutenettet er et kryssende sett med horisontale og vertikale rutenettlinjer som deler rutenettens plass i rutenettceller. Det er to sett med rutenettlinjer; en for å definere kolonnene og en ortogonal for den for å definere radene.display: grid;
enhet, som representerer en brøkdel av ledig plass i nettbeholderen.
Her er den alternative markeringen vi kan bruke hvis vi bruker et rutenettoppsett:
grid-template-columns
Merk at med dette oppsettet gjør vi det ikke trenger en ekstra innpakning for innholdsområdet som vi gjorde for flexbox, siden denne typen layout gjør at vi kan definere elementplassbetegnelse i begge retninger i samme rutenettbeholder.
La oss grave i CSS nå:
grid-template-rows
Vi har definert grid-template-columns: auto 0 auto 1em 1fr;
på containeren vår. auto
og #nav
egenskaper er hver spesifisert som en liste over mellomrom mellom rutenett spor. Disse verdiene er med andre ord ikke posisjonen til rutenettlinjene; heller representerer de mengde plass mellom to spor.
Merk at måleenhetene kan spesifiseres som:
Så med #subnav
vi vil ha:
auto
bredde (#subnav
mellomrom)1em
er på elementnivå, da den kan være tilstede eller ikke, på denne måten unngår vi å ha dobbel takrenne)1fr
bredde (#main
mellomrom)auto
#nav
for #subnav
(tar all gjenværende plass)Her bruker vi tungt grid-template-rows: 5em 1em 1fr 1em 3em;
verdi for sporet, som tillater oss å ha dynamiske kolonner der posisjonen og størrelsen på linjene defineres av deres maksimale innhold. (Vi må derfor spesifisere størrelsene for elementene #header
og #footer
, som vi snart vil gjøre.)
Tilsvarende har vi for radlinjene 1em
som setter vår #header { grid-column: 1 / 6; grid-row: 1 / 2; } #footer { grid-column: 1 / 6; grid-row: 5 / 6; } #main { grid-column: 5 / 6; grid-row: 3 / 4; overflow-y: auto; }
og grid-column
skal fikses og alle elementene mellom å bruke gjenværende ledig plass mens du bruker grid-row
takrenner.
La oss nå se hvordan vi plasserer de faktiske elementene som skal plasseres i vårt definerte rutenett:
grid-column-start
Dette spesifiserer at vi vil at overskriften vår skal være mellom rutenett 1 og 6 (full bredde), og mellom rutenett 1 og 2 for radene våre. Samme for bunntekst, men mellom de to siste linjene (i stedet for de to første). Og hovedområdet er riktig innstilt for den plassen det skal okkupere.
Merk at grid-column-end
og grid-row-start
egenskaper er forkortelse for å spesifisere grid-row-end
/ #nav
og #subnav
/ #nav
, henholdsvis.
OK, så tilbake til #subnav
og #nav { width: 5em; grid-column: 1 / 2; grid-row: 3 / 4; &.expanded { width: 10em; } } #subnav { grid-column: 3 / 4; grid-row: 3 / 4; width: 13em; /* track has gutter of 0, so add margin here */ margin-left: 1em; }
. Siden vi tidligere har plassert #nav
og #subnav
inn i sporet med automatiske verdier, må vi spesifisere hvor brede disse elementene (samme for den utvidede modusen, vi endrer bare bredden og rutenettoppsettet tar seg av resten).
Så nå kan vi bytte mellom
|_+_|og skjul / fjern også
|_+_|og alt fungerer perfekt! Rutenettoppsett lar oss også bruke aliaser for linjene våre, så til slutt endrer rutenettet ikke ut koden ettersom den er tilordnet et navn og ikke en rutenettlinje. Definitivt ser frem til at dette blir bredere støttet av flere nettlesere.
Selv med klassiske CSS-teknikker er det mye mer som kan oppnås enn mange nettutviklere innser eller utnytter. Når det er sagt, kan mye av dette være kjedelig og kan innebære hardkoding av verdier gjentatte ganger gjennom et stilark.
CSS3 har begynt å levere mye mer sofistikerte og fleksible layoutteknikker som er betydelig enklere å programmere, og som unngår mye av kjedsomheten fra tidligere CSS-spesifikasjoner.
Å mestre disse teknikkene og paradigmene - både for CSS2 og CSS3 - er viktig for å utnytte alt CSS har å tilby for å optimalisere både brukeropplevelsen og kvaliteten på koden din. Denne artikkelen representerer egentlig bare toppen av isfjellet av alt det er å lære og alt som kan oppnås med kraften og fleksibiliteten til CSS. Ha på det!
I slekt: * Utforske SMACSS: Skalerbar og modulær arkitektur for CSS *