Het boek van de maand oktober is Handboek HTML5 en CSS3, 5de editie van Peter Doolaard. Deze maand bespreken we het boek, geven we op dit blog wat voorproefjes uit het boek. Dit is deel 3 uit een serie over het maken van een HSL-kleurenkiezer met HTML, CSS en wat JavaScript. Lees ook deel 1, deel 2 en deel 4. Bezoek ook de site Handboek HTML5 en CSS3.
Tijd voor het vervolg van een serie over het maken van je eigen HSL-kleurkiezer. In deel 2 is met hulp van het schaduw-DOM de basisopmaak voor de regelaars ingesteld en kreeg de tintregelaar een kleurverloop volgens het HSL-systeem. Die kleur is niet meer dan een achtergrond. De werkelijke waarde komt uit het attribuut value. Hetzelfde geldt voor de andere regelaars. Met JavaScript kunnen we die waarden lezen en verwerken tot een CSS-kleurdeclaratie of de inhoud van een tekstveld.
De laatste opmaakregels
Er ontbreekt nog opmaak voor het kleurvak, het invoervak en de knoppen. Die voegen we nu eerst toe. De CSS bevat geen bijzonderheden.
.color-box {
border: 1px solid black;
height: 100px;
margin: 6px 0 2px;
}
input[type="text"] {
-webkit-appearance: none;
border: none;
font-size: 1.25em;
margin: 2px 0;
outline: 1px solid black;
padding: 2px;
text-align: center;
}
button {
border: none;
outline: 1px solid black;
font-size: 1.25em;
margin: 2px 0;
padding: 4px;
}
Terug naar het doel
Wat was ook alweer het doel van de kleurkiezer?
- Drie regelaars bieden waarmee je een HSL-kleur kunt maken.
- Een veld tonen waarin de actuele kleur is te zien.
- Een invoerveld (alleen-lezen) bieden waarin de waarde van de actuele kleur is te zien en kan worden gekopieerd naar het klembord.
Voor die eisen moeten we een volwaardige HSL-kleur kunnen samenstellen. Dat lukt alleen met regelaars die echt wat doen.
Van schuifregelaar naar kleur
We willen:
- de waarden van de drie regelaars combineren tot een geldige HSL-kleurwaarde;
- de resulterende kleur weergeven in een kleurvak;
- de code van die kleur als CSS-declaratie tonen in een invoerveld.
Tijd voor wat JavaScript!
De JavaScript-code kan op twee manieren worden gebruikt (maar de tweede methode heeft de voorkeur).
- Typ de JavaScript-code in een blok
<script> ... </script>
onder in het HTML-bestand, vlak boven de sluittag</body>
. - Typ de JavaScript-code in een afzonderlijk bestand met de naam script.js (de naam is vrije keus, de extensie moet .js zijn). Typ onder in het HTML-bestand, vlak boven de sluittag
</body>
, de HTML-code<script src="script.js">
.
Elk element op een HTML-pagina kan worden gevonden en gemanipuleerd met JavaScript. Sterker nog: je kunt elementen aan de pagina toevoegen en ze eruit verwijderen. Hetzelfde kan met HTML-attributen, CSS-klassen, inline stijlen en tekst. Dit is mogelijk dankzij het Document Object Model (DOM). Je kunt ook reageren op gebeurtenissen (events). Klikken (op een link of knop) is een gebeurtenis. De stand van een schuifregelaar veranderen is ook een gebeurtenis. Het is allemaal precies wat we nodig hebben.
Om een element te kunnen manipuleren hebben we een verwijzing naar dat element nodig. Omdat het telkens om een bepaald element gaat, gebruiken we de selector id
als kenmerk. We pikken het element uit het document en wijzen het toe aan een variabele. We kunnen dan de variabele gebruiken als we dat bepaalde element nodig hebben voor een bewerking.
Nu is het belangrijk dat alle elementen zijn geladen voordat we op zoek gaan naar een bepaald element. Daarvoor is de gebeurtenis DOMContentLoaded
. Om te beginnen luisteren we op het document of de gebeurtenis DOMContentLoaded
heeft plaatsgevonden. Pas als dat zo is, gaan we verder.
document.addEventListener('DOMContentLoaded', () => {
// code die wordt uitgevoerd als alle elementen zijn geladen
});
Nu maken we variabelen (const
) voor de schuifregelaars. Elk element dat we met JavaScript willen benaderen, hebben we in de HTML een id
gegeven. De namen zijn een persoonlijke keus. We maken ook gelijk variabelen voor het kleurvak en het invoerveld met de kleurcode.
document.addEventListener('DOMContentLoaded', () => {
const colorSlider = document.getElementById('color-slider');
const saturatSlider = document.getElementById('saturat-slider');
const lightSlider = document.getElementById('light-slider');
const colorBox = document.getElementById('color-box');
const colorValueField = document.getElementById('color-value-field');
});
// dit sluit het luisteren naar DOMContentLoaded af
In de code kunnen we nu de regelaar voor de kleur benaderen met de variabele colorSlider
. Om de inhoud van het attribuut value
te krijgen, gebruiken we colorSlider.value
.
Aangezien we de waarde van de kleurregelaars regelmatig nodig hebben, maken we ook daar variabelen voor. Die krijgen de waarde die we bij het starten van de app willen gebruiken.
// voorgaande code is weggelaten
let hue = 180;
let sat = 100;
let light = 50;
}); // dit sluit het luisteren naar DOMContentLoaded af
Nu kunnen we in de interface eindelijk een kleur en een kleurcode weergeven. De kleurcode komt in het invoerveld:
// voorgaande code is weggelaten
colorValueField.setAttribute('value', `hsl(${hue},${sat}%,${light}%)`);
colorBox.style.backgroundColor = colorValueField.value;
}); // dit sluit het luisteren naar DOMContentLoaded af
Wat gebeurt hier!?
- Het invoerveld wordt benaderd via de variabele
colorValueField
. - Aan het element voegen we met de methode
setAttribute(naam, waarde)
het attribuut met de naamvalue
toe. De waarde is een combinatie van tekst en variabelen. De tekst wordt letterlijk weergegeven en van de variabelen wordt de inhoud getoond. (Dit werkt doordat de hele waarde tussen backticks (het achteroverhellende aanhalingsteken op de toets ~) staat en de variabelen tussen accolades met een dollarteken ervoor.) Dat geeft als resultaathsl(180, 100%, 50%)
. Dit resultaat wordt letterlijk ingevuld bij de CSS-eigenschapbackground-color
van het kleurvak. Deze eigenschap wordt als inline opmaakregel aan het element toegevoegd. In de Inspector (F12) zie je dus staan:
<div class="color-box" id="color-box" style="background-color: rgb(0, 255, 255);"
</div>
Verwarrend kan zijn dat hier geen HSL te bekennen is. Dat komt doordat de browser HSL direct omzet naar RGB. Maar waar het om gaat, is dat met JavaScript de achtergrondkleur van het kleurvak (colorBox
) is ingesteld op de CSS-kleurwaarde die is opgeslagen in het attribuut value
van het element in de variabele colorValueField
.
Tint, verzadiging en helderheid instellen
We kunnen nu ook de regelaars voor tint, verzadiging en helderheid instellen op de beginwaarden uit de variabelen hue
, sat
en light
.
// voorgaande code is weggelaten
colorSlider.setAttribute('value', hue);
saturatSlider.setAttribute('value', sat);
saturatSlider.style.backgroundImage = `linear-gradient(to right, hsl(${hue},0%,${light}%), hsl(${hue},100%,${light}%))`;
lightSlider.setAttribute('value', light);
lightSlider.style.backgroundImage = 'linear-gradient(to right, black, white)';
}); // dit sluit het luisteren naar DOMContentLoaded af
De beginwaarde voor de tint is 180. De beginwaarde voor verzadiging is 100%. De achtergrondkleur van die regelaar is gekoppeld aan de tint (de waarde van hue
) en aan de helderheid (light
). De actuele kleur wordt getoond in een kleurverloop van 0% naar 100% verzadiging. Net als bij de kleurregelaar is de achtergrondkleur vooral een hulpmiddel voor de gebruiker. De echte waarde zit in het attribuut value
van de regelaar.
De regelaar voor de helderheid heeft als achtergrond gewoon een verloop van zwart (0% helderheid) naar wit (100% helderheid). De beginwaarde is 50%.
Het verschuiven van de kleurregelaar verwerken
Het schuiven aan een schuifregelaar levert een gebeurtenis op: input. We kunnen luisteren of die gebeurtenis optreedt en daarop reageren. De volgende code handelt het verschuiven van de kleurregelaar af:
// voorgaande code is weggelaten
colorSlider.addEventListener('input', () => {
hue = colorSlider.value;
saturatSlider.style.backgroundImage = `linear-gradient(to right, hsl(${hue},0%,${light}%), hsl(${hue},100%,${light}%))`;
colorValueField.setAttribute('value', `hsl(${hue},${sat}%,${light}%)`);
colorBox.style.backgroundColor = colorValueField.value;
});
}); // dit sluit het luisteren naar DOMContentLoaded af
Wat gebeurt hier?
Er wordt geluisterd of op het element colorSlider
de gebeurtenis input
optreedt. Als dat zo is, wordt een functie uitgevoerd. De functie zorgt ervoor dat:
- de variabele
hue
(tint) de waarde van de nieuwe stand van de regelaar (0 tot 360) krijgt; - het kleurverloop in de achtergrond van de regelaar voor de verzadiging opnieuw wordt opgebouwd met de nieuwe waarde van
hue
; - het attribuut
value
van het invoerveld met de waarde vanhue
wordt bijgewerkt naar de nieuwe kleur. Het veld toont dus de CSS voor de huidige HSL-kleur; - de achtergrondkleur van het kleurvak de waarde van het invoerveld krijgt; dat is de CSS voor de huidige HSL-kleur.
Het verschuiven van de verzadiginsgregelaar verwerken
Ook als regelaar voor de verzadiging wordt verschoven, wordt een functie uitgevoerd.
// voorgaande code is weggelaten
saturatSlider.addEventListener('input', () => {
sat = saturatSlider.value;
saturatSlider.style.backgroundImage = `linear-gradient(to right, hsl(${hue},0%,${light}%), hsl(${hue},100%,${light}%))`;
colorValueField.setAttribute('value', `hsl(${hue},${sat}%,${light}%)`);
colorBox.style.backgroundColor = colorValueField.value;
});
}); // dit sluit het luisteren naar DOMContentLoaded af
Wat gebeurt hier?
- De variabele
sat
(verzadiging) krijgt de waarde van de nieuwe stand van de regelaar (0 tot 100). - Het kleurverloop in de achtergrond van de regelaar voor de verzadiging wordt opnieuw opgebouwd met de nieuwe waarde van
sat
. - Het attribuut
value
van het invoerveld wordt met de waarde van sat bijgewerkt naar de nieuwe kleur. Het veld toont dus de CSS voor de huidige HSL-kleur. - De achtergrondkleur van het kleurvak krijgt de waarde van het invoerveld: de CSS voor de huidige HSL-kleur.
Dit klinkt bekend? Het zijn inderdaad dezelfde stappen als bij de kleurregelaar.
Het verschuiven van de helderheidsregelaar verwerken
Als de helderheid wordt aangepast, verandert de waarde van de variabele light
(0 tot 100). Met die nieuwe waarde wordt de achtergrondkleur van de verzadigingsregelaar en van het kleurvak aangepast. Het invoerveld toont de nieuwe CSS-waarde voor de HSL-kleur.
// voorgaande code is weggelaten
lightSlider.addEventListener('input', () => {
light = lightSlider.value;
saturatSlider.style.backgroundImage = `linear-gradient(to right, hsl(${hue},0%,${light}%), hsl(${hue},100%,${light}%))`;
colorValueField.setAttribute('value', `hsl(${hue},${sat}%,${light}%)`);
colorBox.style.backgroundColor = colorValueField.value;
});
}); // dit sluit het luisteren naar DOMContentLoaded af
De knoppen aan het werk zetten
We hebben twee knoppen, Kopieer en Herstel, maar die doen nog niet wat er van ze wordt verwacht. Ook bij de knoppen gaan we luisteren naar een gebeurtenis: click
. Wordt er geklikt, dan wordt een functie uitgevoerd.
Eerst maken we boven in het script variabelen met verwijzingen naar de twee elementen <button>
. Voeg ze toe onder de andere variabelen:
// voorgaande code is weggelaten
const btnCopyColorValue = document.getElementById('btn-copy-color-value');
const btnReset = document.getElementById('btn-reset');
Dan laten we luisteren naar de klikgebeurtenissen. De code komt onder de andere luisteraars.
// voorgaande code is weggelaten
btnCopyColorValue.addEventListener('click', (e) => {
e.preventDefault();
colorValueField.select();
document.execCommand('copy');
});
btnReset.addEventListener('click', () => {
hue = 180;
sat = 100;
light = 50;
colorSlider.setAttribute('value', hue);
saturatSlider.setAttribute('value', sat);
lightSlider.setAttribute('value', light);
colorValueField.setAttribute('value', `hsl(${hue},${sat}%,${light}%)`);
colorBox.style.backgroundColor = colorValueField.value;
saturatSlider.style.backgroundImage = `linear-gradient(to right, hsl(${hue},0%,${light}%), hsl(${hue},100%,${light}%))`;
});
});// dit sluit het luisteren naar DOMContentLoaded af
Wat gebeurt hier?
Eerst de kopieerknop. Een <button>
heeft verzenden als standaardactie (submit
). Maar wij willen kopiëren, niet verzenden. Met e.preventDefault()
voorkomen we dat de standaardactie wordt uitgevoerd. De opdracht colorValueField.select();
selecteert de inhoud van het invoervak. De opdracht document.execCommand('copy');
kopieert die inhoud naar het klembord.
Opmerking: In de HTML kan een <button>
ook het attribuut type="button"
krijgen. Dan heeft de knop geen standaardactie en is de opdracht e.preventDefault()
niet nodig.
Dan de herstelknop.
De variabelen voor tint, verzadiging en helderheid worden op de beginwaarden gezet. Met die variabelen wordt van elke regelaar het attribuut value
ingesteld. Vervolgens worden de variabelen gebruikt om het invoerveld, het kleurvak en de verzadigingsregelaar opnieuw in te stellen.
Opmerking: Het ‘midden’ van de schuifregelaar is het nulpunt. Bij een reset zonder extra instellingen komt een schuifjes dus vanzelf in het midden. Het is daarom niet per se nodig om de tint en de helderheid in de code in te stellen.
Opmerking: De JavaScript-code kan korter en efficiënter, maar daar wordt de code niet duidelijker van. Vandaar dit uitgebreide voorbeeld.
De volgende aflevering
De kleurkiezer doet nu alles wat die moet doen. Het enige wat nog ontbreekt is de overlay met de informatie over het gebruik. Die maken we in deel 4.
Dit was deel 3 van de serie. Lees ook deel 1 van de serie, deel 2 en deel 4 .

Peter Doolaard is auteur van het Handboek HTML5 en CSS3. Dat geeft een behoorlijk compleet overzicht van wat HTML en CSS te bieden hebben. Hij werkt nu aan een nieuw boek: Websites bouwen met HTML, CSS en JavaScript. Een praktisch doe-boek, met vragen, opdrachten en projecten. En natuurlijk uitleg over HTML-elementen, CSS-eigenschappen en JavaScript-opdrachten. De komende tijd publiceert Computer Creatief artikelen die je een idee geven van wat je van het nieuwe boek kunt verwachten. Bekijk alle boeken van Peter.
Goed om te zien dat het artikel je tot het einde toe heeft kunnen interesseren. De meeste artikelen op dit blog worden geschreven door de auteurs van
uitgeverij Van Duuren Media.
Ben je geïnteresseerd in verdere verdieping of meer praktische toepassingen? Klik op onderstaande banner voor het meest actuele overzicht.