Zephyrnet-logo

Voorwaardelijk stylen van geselecteerde elementen in een rastercontainer

Datum:

Kalenders, winkelwagentjes, galerijen, bestandsverkenners en online bibliotheken zijn enkele situaties waarin selecteerbare items worden weergegeven in rasters (dwz vierkante roosters). Je weet wel, zelfs die veiligheidscontroles die je vragen om alle afbeeldingen met zebrapaden of wat dan ook te selecteren.

🧐

Ik heb een nette manier gevonden om selecteerbare opties in een raster weer te geven. Nee, niet die reCAPTCHA opnieuw maken, maar gewoon meerdere items kunnen selecteren. En wanneer twee of meer aangrenzende items zijn geselecteerd, kunnen we slim . gebruiken :nth-of-type combinators, pseudo-elementen en de :checked pseudo-klasse om ze zo te stylen dat ze er gegroepeerd uitzien.

Het hele idee van combinators en pseudos om de afgeronde selectievakjes te krijgen, kwam van een vorig artikel dat ik schreef. Het was een eenvoudig ontwerp met één kolom:

Deze keer wordt het afrondingseffect echter toegepast op elementen langs zowel de verticale als de horizontale as op een raster. Je hoeft hiervoor mijn laatste artikel over checkbox-styling niet gelezen te hebben, want ik ga hier alles bespreken wat je moet weten. Maar als je geïnteresseerd bent in een afgeslankte kijk op wat we in dit artikel doen, dan is dat de moeite van het bekijken waard.

Voor we beginnen…

Het is handig voor u om kennis te nemen van een paar dingen. Ik gebruik bijvoorbeeld statische HTML en CSS in mijn demo omwille van de eenvoud. Afhankelijk van uw toepassing moet u mogelijk het raster en de items daarin dynamisch genereren. Ik laat praktische controles op toegankelijkheid achterwege om me op het effect te concentreren, maar dat soort dingen zou je zeker in een productieomgeving willen overwegen.

Ook gebruik ik CSS Grid voor de lay-out. Ik zou hetzelfde aanraden, maar het is natuurlijk slechts een persoonlijke voorkeur en je kilometerstand kan variëren. Voor mij stelt het gebruik van raster me in staat om gemakkelijk broer/zus-kiezers te gebruiken om de items van een item te targeten ::before en ::after pseudo's.

Dus, welke lay-outstandaard u ook in uw toepassing wilt gebruiken, zorg ervoor dat de pseudos nog steeds kunnen worden getarget in CSS en zorg ervoor dat de lay-out intact blijft in verschillende browsers en schermen.

Laten we nu beginnen

Zoals je misschien hebt opgemerkt in de eerdere demo, wijzigt het aan- en uitvinken van een selectievakje het ontwerp van de vakjes, afhankelijk van de selectiestatus van de andere selectievakjes eromheen. Dit is mogelijk omdat ik elke doos heb gestyled met behulp van de pseudo-elementen van de aangrenzende elementen in plaats van zijn eigen element.

De volgende afbeelding laat zien hoe de ::before pseudo-elementen van dozen in elk kolom (behalve de eerste kolom) de vakken aan hun linkerkant overlappen, en hoe de ::after pseudo-elementen van dozen in elk rij (behalve de eerste rij) overlappen de vakken hierboven.

Twee rasters met selectievakjes die de plaatsing van voor en na pseudos tonen.

Hier is de basiscode

De opmaak is vrij eenvoudig:

<main>
  <input type=checkbox>
  <input type=checkbox>
  <input type=checkbox>
  <!-- more boxes -->
</main>

Er is iets meer aan de hand in de eerste CSS. Maar eerst het raster zelf:

/* The grid */
main {
  display: grid;
  grid:  repeat(5, 60px) / repeat(4, 85px);
  align-items: center;
  justify-items: center;
  margin: 0;
}

Dat is een raster van vijf rijen en vier kolommen die selectievakjes bevatten. Ik besloot om het standaard uiterlijk van de selectievakjes weg te vagen en ze vervolgens mijn eigen lichtgrijze achtergrond en superronde randen te geven:

/* all checkboxes */
input {
  -webkit-appearance: none;
  appearance: none;
  background: #ddd;
  border-radius: 20px;
  cursor: pointer;
  display: grid;
  height: 40px;
  width: 60px;
  margin: 0;
}

Merk ook op dat de selectievakjes zelf rasters zijn. Dat is de sleutel voor het plaatsen van hun ::before en ::after pseudo-elementen. Daarover gesproken, laten we dat nu doen:

/* pseudo-elements except for the first column and first row */
input:not(:nth-of-type(4n+1))::before,
input:nth-of-type(n+5)::after {
  content: '';
  border-radius: 20px;
  grid-area: 1 / 1;
  pointer-events: none;
}

We selecteren alleen de pseudo-elementen van selectievakjes die niet in de eerste kolom of de eerste rij van het raster staan. input:not(:nth-of-type(4n+1)) begint bij het eerste selectievakje en selecteert vervolgens de ::before van elk vierde item vanaf daar. Maar merk op dat we zeggen: :not(), dus echt wat we doen is het overslaan van de ::before pseudo-element van elk vierde selectievakje, te beginnen bij het eerste. Dan passen we stijlen toe op de ::after pseudo van elk selectievakje vanaf de vijfde.

Nu kunnen we zowel de ::before en ::after pseudos voor elk selectievakje dat zich niet in de eerste kolom of rij van het raster bevindt, zodat ze respectievelijk naar links of omhoog worden verplaatst en ze standaard worden verborgen.

/* pseudo-elements other than the first column */
input:not(:nth-of-type(4n+1))::before {
  transform: translatex(-85px);
}

/* pseudo-elements other than the first row */
input:nth-of-type(n+5)::after {
 transform: translatey(-60px);
}

Het stylen van de :checked staat

Nu komt het stylen van de selectievakjes wanneer ze in een :checked staat. Laten we ze eerst een kleur geven, zeg a limegreen achtergrond:

input:checked { background: limegreen; }

Een aangevinkt vakje moet alle aangrenzende vakjes opnieuw kunnen opmaken. Met andere woorden, als we het elfde selectievakje in het raster selecteren, zouden we ook in staat moeten zijn om de vakken eromheen bovenaan, onderaan, links en rechts op te maken.

Een vier-bij-vijf raster van vierkanten genummerd van één tot en met 20. 11 is geselecteerd en 7, 10, 12 en 15 zijn gemarkeerd.

Dit wordt gedaan door de juiste pseudo-elementen te targeten. Hoe doen we dat? Welnu, het hangt af van het werkelijke aantal kolommen in het raster. Hier is de CSS als twee aangrenzende vakjes zijn aangevinkt in een 5⨉4-raster:

/* a checked box's right borders (if the element to its right is checked) */
input:not(:nth-of-type(4n)):checked + input:checked::before {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  background: limegreen;
}
/* a checked box's bottom borders (if the element below is checked) */
input:nth-last-of-type(n+5):checked + * + * + * + input:checked::after {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
  background: limegreen;
}
/* a checked box's adjacent (right side) checked box's left borders */
input:not(:nth-of-type(4n)):checked + input:checked + input::before {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  background: limegreen;
}
/* a checked box's adjacent (below) checked box's top borders */
input:not(:nth-of-type(4n)):checked + * + * + * +  input:checked + input::before {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
  background: limegreen;
}

Als u wilt, kunt u de bovenstaande code dynamisch genereren. In een typisch raster, bijvoorbeeld een afbeeldingengalerij, zal het aantal kolommen klein zijn en waarschijnlijk een vast aantal items, terwijl de rijen mogelijk blijven toenemen. Vooral als het is ontworpen voor mobiele schermen. Daarom is deze aanpak nog steeds een efficiënte manier om te gaan. Als uw toepassing om de een of andere reden beperkte rijen heeft en kolommen uitbreidt, overweeg dan om het raster zijwaarts te draaien, omdat CSS Grid met een stroom items ze van links naar rechts en van boven naar beneden rangschikt (dwz rij voor rij) .

We moeten ook styling toevoegen voor de laatste selectievakjes in het raster - ze worden niet allemaal gedekt door pseudo-elementen, omdat ze de laatste items in elke as zijn.

/* a checked box's (in last column) left borders */
input:nth-of-type(4n-1):checked + input:checked {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
/* a checked box's (in last column) adjacent (below) checked box's top borders */
input:nth-of-type(4n):checked + * + * + * + input:checked {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

Dat zijn een paar lastige selectors! De eerste…

input:nth-of-type(4n-1):checked + input:checked

... zegt eigenlijk dit:

een aangevinkt <input> element naast een aangevinkt <input> in de voorlaatste kolom.

En de nth-of-type wordt als volgt berekend:

4(0) - 1 = no match
4(1) - 1 = 3rd item
4(2) - 1 = 7th item
4(3) - 1 = 11th item
etc.

We beginnen dus bij het derde selectievakje en selecteren daar elke vierde. En als een selectievakje in die volgorde is aangevinkt, stylen we ook de aangrenzende selectievakjes, als ze ook zijn aangevinkt.

En deze regel:

input:nth-of-type(4n):checked + * + * + * + input:checked

Zegt dit:

An <input> element, mits aangevinkt, direct grenst aan een element, dat direct grenst aan een ander element, dat ook direct grenst aan een ander element, dat op zijn beurt direct grenst aan een <input> element dat zich in een aangevinkte staat bevindt.

Dat betekent dat we elk vierde selectievakje selecteren dat is aangevinkt. En als een selectievakje in die volgorde is aangevinkt, dan stylen we het volgende vierde selectievakje van dat selectievakje als het ook is aangevinkt.

In gebruik nemen

Waar we zojuist naar hebben gekeken, is het algemene principe en de logica achter het ontwerp. Nogmaals, hoe nuttig het is in uw toepassing, hangt af van het rasterontwerp.

Ik heb ronde randen gebruikt, maar je kunt andere vormen proberen of zelfs experimenteren met achtergrondeffecten (Temani heeft u gedekt voor ideeën). Nu je weet hoe de formule werkt, is de rest helemaal aan je verbeelding.

Hier is een voorbeeld van hoe het eruit zou kunnen zien in een eenvoudige kalender:

Nogmaals, dit is slechts een ruw prototype met statische opmaak. En er zouden heel veel toegankelijkheidsoverwegingen zijn om te overwegen in een kalenderfunctie.


Het zit er op! Best netjes toch? Ik bedoel, er is niets precies "nieuws" aan wat er gebeurt. Maar het is een goed voorbeeld van dingen selecteren in css. Als we meer geavanceerde selectietechnieken onder de knie hebben die combinators en pseudos gebruiken, dan kunnen onze stylingvaardigheden veel verder reiken dan het stylen van één item - zoals we zagen, kunnen we items conditioneel stylen op basis van de staat van een ander element.

spot_img

Laatste intelligentie

spot_img

Chat met ons

Hallo daar! Hoe kan ik u helpen?