Hvordan det Romerske Imperiet Laget Ren CSS Koble 4 Mulig

0
19

Eksperimenter er en morsom unnskyldning for å lære de nyeste triks, tenke nye ideer, og presse grensene. “Pure CSS” demoer har blitt en ting for en stund, men nye muligheter åpner opp som nettlesere og CSS selv utvikler seg. CSS og HTML preprocessors hjalp også scenen gå videre. Noen ganger preprocessors er brukt for hardcoding alle mulige scenario, for eksempel, lange strenger av :kontrollert og tilstøtende søsken velgere.

I denne artikkelen, vil jeg gå gjennom sentrale ideer for en Ren CSS Koble til 4 spill jeg bygget. Jeg prøvde å unngå hardcoding så mye som jeg kan i mitt eksperiment og jobbet uten preprocessors å fokusere på å holde den resulterende koden kort. Du kan se hele koden og spillet her:

Se Penn Ren CSS Koble 4 av Bence Szabó (@finnhvman) på CodePen.

Viktige begreper

Jeg tror det er noen begreper som anses som viktige i “pure CSS” sjangeren. Vanligvis skjema elementene er brukt for styring av statlige og fange brukeren handlinger. Jeg var spent da jeg fant folk bruker < – knappen type=”reset” – > for å tilbakestille eller start et nytt spill. Alt du trenger å gjøre er å legge din elementer i en <form> – koden, og legg til-knappen. I min mening er dette en mye renere løsning enn å ha for å oppdatere siden.

Mitt første steg var å skape et form-element og deretter kaste en haug av innganger til det for spor og legge til reset-knappen. Her er en veldig enkel demonstrasjon av < – knappen type=”reset”> i aksjon:

Se Penn Ren HTML Form for Tilbakestilling av Bence Szabó (@finnhvman) på CodePen.

Jeg ønsket å ha fin visuell for denne demoen hvis du vil gi en full opplevelse. I stedet for å trekke i et eksternt bilde for bord eller plater, jeg brukte en radial-gradient(). En fin ressurs jeg bruker ofte er Lea Verou er CSS3 Mønstre Galleri. Det er en samling av mønstre laget av graderinger, og de er redigerbare også! Jeg brukte currentcolor, som kom ganske hendig for platen mønster. Jeg har lagt til et topp-og gjenbrukt min Pure CSS-Ripple-Knappen.

På dette punktet layout og plate design allerede var endelig, bare spillet ikke fungere i det hele tatt

Slippe plater på brettet

Neste jeg aktiverte brukere til å ta sin svinger slippe plater på Koble til 4 bord. I Koble til 4 spillere (en rød og en gul) drop-plater til kolonner i vekslende svinger. Det er 7 kolonner og 6 rader (42 slots). Hvert spor kan være tom eller okkupert av en rød eller gul plate. Så, en spilleautomat kan ha tre tilstander (tom, rød eller gul). Plater som slippes i den samme kolonnen er stablet på hverandre.

Jeg startet ut ved å plassere to rutene for hvert spor. Når de er begge ukontrollert sporet regnes som tomme, og når en av dem er sjekket tilsvarende spiller har sin plate i det.

Mulige tilstand av å ha dem begge sjekket bør unngås ved å skjule dem når noen av dem er sjekket. Disse boksene er umiddelbar søsken, så når den første av et par er sjekket at du kan skjule både ved hjelp av :sjekket pseudo-klasse og tilstøtende søsken combinator (+). Hva hvis den andre er sjekket? Du kan skjule andre, men hvordan påvirker det første? Vel, det er ingen tidligere søsken selector, det er bare ikke hvordan CSS-velgere arbeid. Jeg hadde for å avvise denne ideen.

Faktisk, en avmerkingsboks kan ha tre tilstander av seg selv, det kan være i ubestemt tilstand. Problemet er at du ikke kan sette den i ubestemt tilstand med HTML alene. Selv om du kan, neste klikk på avmerkingsboksen ville alltid gjøre det forvandle seg til en kontrollert tilstand. Å tvinge den andre spilleren til å dobbel-klikke når de gjør sine trekk er upålitelige og uakseptabelt.

Jeg ble sittende fast på MDN dok :ubestemmelige og la merke til at radio-innganger har også ubestemt tilstand. Radio knapper med samme navn er i denne tilstanden når de er kontrollert. Wow, det er en faktisk opprinnelige tilstand! Hva er virkelig gunstig er det å sjekke siste søsken har også en effekt på det tidligere! Dermed er jeg fylt styret med 42 par av radio-innganger.

I ettertid, smart bestilling og bruk av etiketter med enten avkrysningsbokser eller radioknapper ville ha gjort susen, men jeg tok ikke hensyn til etiketter for å være et alternativ for å gjøre koden enklere og kortere.

Jeg ønsket å ha store områder for samhandling for å ha fin UX, så jeg syntes det er rimelig å la spillerne gjøre et trekk ved å klikke på en kolonne. Jeg stablet kontroller av samme kolonne på hverandre ved å legge absolutt og relativ posisjonering for de aktuelle elementene. På denne måten bare de laveste tomt spor kan velges innenfor en kolonne. Jeg er omhyggelig satt tidspunktet for overgang av platen falle per rad og timingen funksjon er tilnærmet en kvadratisk kurve for å ligne realistisk fritt fall. Så langt bitene i puslespillet kom godt sammen, selv om animasjonen nedenfor viser klart at kun de røde kan spilleren gjør sine trekk.

Selv om alle kontrollene er det bare røde plater kan bli droppet på styret

Den klikkbare områder av radio-innganger er visualisert med farget, men semi-transparent rektangler. De gule og røde innganger er stablet over hverandre seks ganger(=seks rader) per kolonne, forlater de røde input av den laveste rad på toppen av bunken. Blandingen av rødt og gult skaper orangish farge som kan sees på bordet ved start. Mindre tomme slots er tilgjengelig i en kolonne, er det mindre intens dette orangish farge blir siden radio data ikke vises med en gang de er ikke :ubestemt. På grunn av den røde innspill alltid være nettopp over den gule innspill i hver spilleautomat, bare den rød-spilleren er i stand til å foreta trekk.

Sporing slår

Jeg bare hatt en svak idé, og mange håper at jeg kan liksom løse bytte svinger mellom de to spillerne med den generelle søsken-velgeren. Konseptet var å la den rød-spiller tar slå når antall sjekket innganger var enda (0, 2, 4, etc.) og la den gule spiller tar slå når dette nummeret var merkelig. Snart innså jeg at den generelle søsken velgeren ikke (og bør ikke!) arbeid på den måten jeg ønsket.

Så er det en veldig opplagt valg var å eksperimentere med nth-velgere. Men tiltrekker det var å bruke den selv og ulike søkeord, jeg kjørte inn i en blindvei. Av :nth-child selector “teller” barna i en overordnet, uavhengig av type, klasse, pseudo-klasse, uansett. Av :nth-of-type selector “teller” barn av en type i en overordnet, uavhengig av klasse eller pseudo-klasse. Så problemet er at de ikke kan regne basert på :kontrollert tilstand.

Vel CSS tellere teller også, så hvorfor ikke gi dem en sjanse? En vanlig bruk av tellere er til antall overskrifter (selv i flere nivåer) i et dokument. De er styrt av CSS-regler, kan bli utsatt for vilkårlig nullstilles på alle punkt og deres tilvekst (eller minsk!) verdier kan være et heltall. Tellerne vises av telleren () – funksjonen i innhold eiendom.

Det enkleste trinnet var å sette opp en teller og teller :sjekket innganger i Connect 4 rutenett. Det er bare to problemer med denne tilnærmingen. Den første er at du ikke kan utføre arithmetics på et møte for å oppdage om det er partall eller oddetall. Det andre er at du ikke kan bruke CSS-regler elementer basert på telleren.

Jeg klarte å overvinne den første problemet ved å gjøre telleren binære. Verdien av telleren er i utgangspunktet null. Når den røde spilleren sjekker sine radio-knappen telleren, og øker med én. Når den gule spilleren sjekker sine radio-knappen telleren er decremented etter en, og så videre. Derfor telleren vil være enten null eller én, partall eller oddetall.

Løse det andre problemet kreves mye mer kreativitet (les: hack). Som nevnt tellere kan vises, men kun i ::før og ::etter pseudo-elementer. Det er en no-brainer, men hvordan kan de påvirke andre elementer? I det minste telleren kan endre bredden av pseudo-element. Forskjellige tall har forskjellige bredder. Karakter 1 er vanligvis tynnere enn 0, men det er noe som er svært vanskelig å kontrollere. Hvis antall tegn endring snarere enn tegnet seg som følge bredde endringen er mer kontrollerbar. Det er ikke uvanlig å bruke romertall med CSS-tellere. En og to representert i romertall er de samme karakter én gang og to ganger-og så er sine bredder i punkter.

Min idé var å feste radio knapper av en spiller (gul) til venstre, og fest radio knapper av den andre spilleren (rød) til høyre i den felles overordnede container. I utgangspunktet, de røde knappene er lagt over på den gule knappene, deretter bredden endring av beholderen ville føre til at den rød-knappene for å “gå seg bort” og avsløre de gule knappene. En lignende virkelige verden konseptet er glidende vindu med to ruter, en rute er fast (gule knapper), den andre er slidable (rød knapp) over den andre. Forskjellen er at i spillet bare halvparten av vinduet er synlig.

Så langt, så bra, men jeg var fortsatt ikke fornøyd med font-size (og andre font egenskaper) indirekte å kontrollere bredde. Jeg trodde brev-avstand ville passe fint her, siden det bare øker størrelsen i én dimensjon. Uventet, selv én bokstav har brev mellomrom (som er gjengitt etter brev), og to bokstaver gjengi brevet avstanden to ganger. Forutsigbar bredder er avgjørende for å gjøre denne pålitelige. Null bredde tegn sammen med single og double brev avstand ville fungere, men det er farlig å angi skrift-størrelse til null. Å definere stor bokstav-avstand (i piksler) og små (1px) font-size gjorde det nesten konsekvent på tvers av alle nettlesere, ja jeg snakker om sub-piksler.

Jeg trengte beholderen bredde til å veksle mellom start størrelse (=w) og minst doble den opprinnelige størrelse (>=2w) for å være i stand til å fullstendig skjule og vise den gule knapper. La oss si at v er gjengitt bredden av ‘jeg’ – tegnet (lavere romerske representasjon, varierer på tvers av nettlesere), og c er gjengitt bredde (konstant) av brev-avstand. Jeg trengte v + c = w til å være sant, men det kunne ikke være, fordi c og n er heltall, men v er ikke-heltall. Jeg endte opp med å bruke min-bredde og maks bredde på egenskaper for å begrense mulig bredde verdier, slik jeg også har endret mulig counter verdier til ” jeg ” og ” iii ” for å sørge for at teksten bredder underflow og overløp begrensninger. I ligninger dette så ut som v + c < w, 3v + 3c > 2w, og v << c, som gir 2/3w < c < w. Konklusjonen er at det letter-avstand har til å være noe mindre enn den opprinnelige bredde.

Jeg har vært resonnement så langt som om pseudo element som viser telleren var den overordnede radio knapper, det er det ikke. Men, la jeg merke til at bredden av pseudo-element endringer bredden av sine overordnede element, og i dette tilfellet foreldrene er i beholderen for radio knapper.

Hvis du tenker ikke kunne dette løses med arabiske tall? Du har rett, vekslende telleren mellom noe sånt som ‘1’ og ‘111’ ville også fungere. Likevel, romertall ga meg ideen i første omgang, og de var også en god unnskyldning for clickbaity tittel, så jeg holdt dem.

Spillerne ta vekslende slår starter med den rød-spiller

Å anvende teknikken diskutert gjør foreldrene beholder av radio-innganger, dobbelt i bredde når en rød inngang er sjekket og gjør det opprinnelige bredde når en gul input er markert. I den opprinnelige bredde beholder den røde innganger er over de gule, men i dobbel bredde beholder den rød-innganger er gått bort.

Gjenkjenne mønstre

I det virkelige liv, Koble 4 styret ikke fortelle deg om du har vunnet eller tapt, men å gi skikkelig tilbakemelding er del av en god brukeropplevelse i noen programvare. Neste mål er å oppdage om en spiller har vunnet spillet. For å vinne spillet en spiller har til å ha fire av sine plater i en kolonne, rad eller diagonal linje. Dette er en veldig enkel oppgave å løse i mange programmeringsspråk, men i ren CSS verden, dette er en stor utfordring. Bryte det ned for å deloppgavene er måten å nærme seg dette systematisk.

Jeg brukte en flex-container som foreldre av radio knapper og plater. En gul radio-knappen, vises et rødt radio-knappen og div for platen hører til en spilleautomat. Slike spor er gjentatt 42 ganger, og som er ordnet i kolonner som brytes. Følgelig, spor i en kolonne er tilstøtende, som gjør gjenkjenne fire i en kolonne den enkleste delen med tilstøtende selector:

<div class=”grid”>
<input type=”radio” name=”slot11″>
<input type=”radio” name=”slot11″>
<div class=”plate”></div>
<input type=”radio” name=”slot12″>
<input type=”radio” name=”slot12″>
<div class=”plate”></div>

<input type=”radio” name=”slot16″>
<input type=”radio” name=”slot16″>
<div class=”plate”></div>

<input type=”radio” name=”slot21″>
<input type=”radio” name=”slot21″>
<div class=”plate”></div>

</div>
/* Rød fire i en kolonne velger */
inngang:sjekket + .plate + inngang + inngang:sjekket + .plate + inngang + inngang:sjekket + .plate + inngang + inngang:sjekket ~ .utfallet

/* Gul fire i en kolonne velger */
inngang:sjekket + inngang + .plate + inngang:sjekket + inngang + .plate + inngang:sjekket + inngang + .plate + inngang:sjekket ~ .utfallet

Dette er en enkel, men stygg løsning. Det er 11 type og klasse velgere lenket sammen per spiller for å dekke tilfelle av fire i en kolonne. Legge til en div med klasse av .resultatet etter elementer av sporene gjør det mulig å betinget vise resultatet melding. Det er også et problem med feilaktig detektering av fire i en kolonne hvor kolonnen er pakket inn, men la oss sette dette problemet til side.

En lignende tilnærming for å oppdage fire på rad ville være virkelig en forferdelig idé. Det ville være 56 velgere lenket sammen per spiller (hvis jeg gjorde regnestykket til høyre), for ikke å nevne at de ville ha en lignende feil av falske påvisning. Dette er en situasjon hvor :nth-child(An+B [S]) eller kolonnen combinators vil komme godt med i fremtiden.

For bedre semantikk man kunne legge til en ny div for hver kolonne og ordne spor elementer i dem. Denne endringen vil også eliminere muligheten for falske påvisning nevnt ovenfor. Så å oppdage fire på rad kunne gå som: velg en kolonne hvor det første røde radio inngang er merket, og velger den tilstøtende søsken kolonnen der den første røde radio-input er markert, og så på to ganger. Dette høres veldig tungvint, og ville kreve “mor” – velgeren.

Å velge den forelder det ikke er mulig, men du velger barnet er. Hvordan vil oppdage fire på rad gå med tilgjengelig combinators og velgere? Velg en kolonne, og velg deretter sin første røde radio innspill hvis det er merket, og velger den tilstøtende kolonnen, og velg deretter sin første røde radio innspill hvis det er merket av, og så på to ganger. Det høres fortsatt tungvint, men det er mulig. Trikset er ikke bare i CSS, men også i HTML, den neste kolonnen har til å være søsken av radio knapper i forrige kolonne opprette en nestet struktur.

<div class=”grid kolonnen”>
<input type=”radio” name=”slot11″>
<input type=”radio” name=”slot11″>
<div class=”plate”></div>

<input type=”radio” name=”slot16″>
<input type=”radio” name=”slot16″>
<div class=”plate”></div>

<div class=”column”>
<input type=”radio” name=”slot21″>
<input type=”radio” name=”slot21″>
<div class=”plate”></div>

<input type=”radio” name=”slot26″>
<input type=”radio” name=”slot26″>
<div class=”plate”></div>

<div class=”column”>

</div>
</div>
</div>
/* Rød fire på rad velgere */
inngang:nth-of-type(2):sjekket ~ .kolonne > input:nth-of-type(2):sjekket ~ .kolonne > input:nth-of-type(2):sjekket ~ .kolonne > input:nth-of-type(2):sjekket ~ .kolonne::etter,
inngang:nth-of-type(4):sjekket ~ .kolonne > input:nth-of-type(4):sjekket ~ .kolonne > input:nth-of-type(4):sjekket ~ .kolonne > input:nth-of-type(4):sjekket ~ .kolonne::etter,

inngang:nth-of-type(12):sjekket ~ .kolonne > input:nth-of-type(12):sjekket ~ .kolonne > input:nth-of-type(12):sjekket ~ .kolonne > input:nth-of-type(12):sjekket ~ .kolonne::etter

Vel semantikk er messed opp, og disse velgere er bare for de rød-spiller (ny runde går for den gule spiller), på den annen side er det ikke arbeid. En liten fordel er at det vil være noen feilaktig registrert kolonner eller rader. Det vises mekanismen for utfallet hadde også til å bli endret, ved å bruke ::etter pseudo element av noen matchende kolonnen er en konsistent løsning når riktig styling er brukt. Som et resultat av dette, en falsk åttende kolonnen har å bli lagt til etter den siste sporet.

Som vi har sett i kodebiten over, bestemte posisjoner i en kolonne er matchet til å oppdage fire på rad. Den samme teknikken kan brukes for å påvise fire i en diagonal ved å justere disse stillingene. Vær oppmerksom på at diagonalene kan finnes i to retninger.

inngang:nth-of-type(2):sjekket ~ .kolonne > input:nth-of-type(4):sjekket ~ .kolonne > input:nth-of-type(6):sjekket ~ .kolonne > input:nth-of-type(8):sjekket ~ .kolonne::etter,
inngang:nth-of-type(4):sjekket ~ .kolonne > input:nth-of-type(6):sjekket ~ .kolonne > input:nth-of-type(8):sjekket ~ .kolonne > input:nth-of-type(10):sjekket ~ .kolonne::etter,

inngang:nth-of-type(12):sjekket ~ .kolonne > input:nth-of-type(10):sjekket ~ .kolonne > input:nth-of-type(8):sjekket ~ .kolonne > input:nth-of-type(6):sjekket ~ .kolonne::etter

Antall velgere har økt vesentlig i det siste run, og dette er definitivt et sted hvor CSS preprocessors kunne redusere lengden av erklæringen. Likevel, jeg tror demo er moderat kort. Det bør være et sted rundt midten på skalaen fra hardcoding en velger for hver mulig vinnende mønster å bruke 4 magiske velgere (kolonne, rad, to diagonaler).

En melding vises når en spiller vinner

Avsluttende smutthull

Noen programvare har edge saker, og de må håndteres. Mulige utfall av et Koble 4 spillet er ikke bare rød, eller gul-spilleren som vinner, men verken spilleren vinne fylle styret kjent som drag. Teknisk er dette tilfelle ikke bryte spillet, eller produsere noen feil, hva er det som mangler, er tilbakemelding til spillerne.

Målet er å oppdage når det er 42 :sjekket radio knapper på styret. Dette betyr også at ingen av dem er i :ubestemt tilstand. Som krever et utvalg til å være laget for radio hver gruppe. Radio knapper er ugyldig, da de er :ubestemmelige, ellers er gyldig. Så jeg har lagt det nødvendige attributt for hver inngang, deretter brukt :gyldig pseudo-klasse på skjemaet for å oppdage tegn.

Trekningen utfallet meldingen vises når brettet er fylt

Som dekker trekke utfallet introdusert en feil. I svært sjeldne tilfeller av gul-spilleren som vinner på siste sving, både seier og uavgjort meldinger skal vises. Dette er fordi deteksjon og vise metode av disse resultatene er ortogonale. Jeg jobbet rundt problemet ved å sørge for at vinne meldingen har en hvit bakgrunn, og er over trekker meldingen. Jeg hadde også til å forsinke fade i overgangen i trekningen melding, så det ville ikke bli blandet med seieren melding overgang.

Den gule vinner meldingen er over uavgjort resultat at den skal vises

Mens mye av radio-knappene er skjult bak hverandre ved absolutt posisjonering, alle av dem i ubestemt staten kan fortsatt nås ved å tabbe gjennom kontroller. Dette gjør det mulig for spillere å slippe deres plater i vilkårlig slots. En måte å håndtere dette på er å bare forby tastatur vekselsvirkningene av tabindex-attributtet: konfigurere den til å -1 betyr at det ikke skal være tilgjengelig via sekvensiell tastaturet for å navigere. Jeg hadde til å forsterke hver radio-inngang med denne egenskapen til å eliminere denne smutthull.

<input type=”radio” name=”slot11″ tabindex=”-1″ nødvendige>
<input type=”radio” name=”slot11″ tabindex=”-1″ nødvendige>
<div class=”plate”></div>

Begrensninger

De mest betydelige ulempen er at styret ikke er responsiv, og det kan fungere på små viewports på grunn av upålitelig løsning for sporing av svinger. Jeg våget ikke å ta risikoen for refactoring til en rask løsning, på grunn av gjennomføringen det føles mye tryggere med faste mål.

Et annet problem er trege sveve på touch-enheter. Å legge til noen interaksjon media spørsmål til de riktige stedene er den enkleste måten å kurere dette, selv om det ville eliminere fritt fall animasjon.

Man kunne kanskje tro at det :ubestemt pseudo-klassen er allerede mye støtte, og det er det. Problemet er at det er bare delvis støttet i enkelte nettlesere. Observere Note 1 i kompatibiliteten tabell: MS IE og Kant ikke støtter dette på radio knapper. Hvis du vil vise demo i disse nettleserne markøren vil slå inn i den ikke-tillatt markør på bordet, dette er en utilsiktet, men noe grasiøs nedbrytning.

Ikke alle nettlesere støtter :ubestemmelige på radio knapper

Konklusjon

Takk for å gjøre det til siste avsnitt! La oss se på noen tall:

  • 140 HTML-elementer
  • 350 (rimelig) linjer av CSS
  • 0 JavaScript
  • 0 eksterne ressurser

Totalt sett er jeg fornøyd med resultatet og tilbakemeldingene var gode. Jeg er sikker lærte mye å gjøre denne demoen, og jeg håper jeg kan dele mye å skrive denne artikkelen!