Praca z CSS

Ze stylowaniem elementów możemy działać na kilka sposobów.

Właściwość style

Najczęściej spotykanym sposobem jest skorzystanie z właściwości style, którą możemy użyć do ustawiania i odczytu stylowania:


const btn = document.querySelector(".button");

btn.addEventListener("click", function() {
    this.style.backgroundColor = "#4BA2EA";
    this.style.fontSize = "1.6rem";
    this.style.borderRadius = "3rem";
    this.style.color = "#F7F781";
});

Zauważ jak odwołujemy się do właściwości CSS. Jeżeli właściwość składa się z jednego słowa, to zapisujemy ją tak jak w css. Jeżeli właściwość składa się z kilku słów oddzielonych myślnikiem, wtedy dla takiej właściwości musimy zastosować zapis CamelCase. Możemy tutaj też zastosować zapis znany z obiektów:


//css
font-size : 1rem;
//js
el.style.fontSize = "1rem";
el.style['font-size'] = "1rem";


//css
background : linear-gradient(#fff, #ddd);
//js
el.style.background = "linear-gradient(#fff, #ddd)";
el.style['background'] = "linear-gradient(#fff, #ddd)";


//css
background-color : rgba(255,255,255,0.5);
//js
el.style.backgroundColor = "rgba(255,255,255,0.5)";
el.style['background-color'] = "rgba(255,255,255,0.5)";


//css
border-width : 2px
//js
el.style.borderWidth = "2px"
el.style['border-width'] = "2px";

Podobne zasady tyczą się odczytu styli, do którego używamy tej samej właściwości:


<div class="module">
    <h3 class="module-title">Przykładowa nazwa artykułu</h3>
    <div class="module-content" style="display:none">
        Lorem ipsum dolor sit amet...
    </div>
    <button type="button" class="button module-button" id="testShowContent">Pokaż treść</button>
</div>

const btn = document.querySelector(".module-button");
const textCnt = btn.previousElementSibling;

btn.addEventListener("click", function() {
    if (textCnt.style.display === "none") {
        textCnt.style.display = "block";
    } else {
        textCnt.style.display = "none";
    }
});

Przykładowa nazwa artykułu

Zauważ, że początkowe ukrycie treści uzyskałem przez display:none zapisane w atrybucie style danego elementu. Wrócimy do tej sprawy poniżej.

setProperty() i getPropertyValue()

Właściwość style udostępnia nam też dodatkowe metody, wśród których 2 kluczowe to:
style.setProperty(propertyName, value, priority*) - służy do ustawiania stylowania. Ostatni opcjonalny parametr priority służy do ewentualnego dodania do danych styli deklaracji !important. Najczęściej jest pomijany.
style.getPropertyValue(property) - służy do pobierania stylowania.


const btn = document.querySelector(".button");

btn.addEventListener("click", function() {
    if (this.style.getPropertyValue("font-size") !== "1.5rem") {
        this.style.setProperty("background-color", "#4BA2EA");
        this.style.setProperty("font-size", "1.5rem");
        this.style.setProperty("border-radius", "3rem");
    } else {
        this.style.setProperty("background-color", "");
        this.style.setProperty("font-size", "");
        this.style.setProperty("border-radius", "");
    }
});

getComputedStyle()

Jeżeli ustawiamy style za pomocą powyższych sposobów, są one wstawiane inline w atrybucie style danego elementu.
Żeby to sprawdzić, odśwież stronę, przejdź do debugera i zbadaj przycisk z pierwszego przykładu. Kliknij na niego i zobacz jak doklejane są style.

style przycisku

Podobna zasada tyczy się odczytu. Jeżeli dany element nie ma ustawionych styli inline (wpisanych z palca, lub za pomocą JS), to nie jesteśmy w stanie ich pobrać:


const btn = document.querySelector("#testInline");
btn.addEventListener("click", function() {
    console.log(this.style['font-size']); //wypisze ""
    console.log(this.style.backgroundColor); //wypisze ""

    this.style['font-size'] = "1.5rem"; //ustawiamy style inline
    this.style.backgroundColor = "#4BA2EA"; //to samo z kolorem tła

    console.log(this.style['font-size']); //wypisze "1.5rem"
    console.log(this.style.backgroundColor); //wypisze "#4BA2EA"
});

Bardzo często będziemy chcieli jednak sprawdzić lub pobrać style, które są zadeklarowane w arkuszach stylów a nie inline w kodzie HTML. Przykładowo powyższy przycisk ma swój wygląd (np. background), który nadała mu klasa .button z pliku ze stylami.

Żeby pobrać takie stylowanie musimy skorzystać z metody window.getComputedStyle(elem, pseudoEl*), która zwraca przeliczone przez przeglądarkę stylowanie. Pierwszy parametr tej metody określa badany element, drugi - opcjonalny pozwala pobierać style dla pseudo elementów. Jeżeli nie chcemy badać pseudo elementów, wtedy używamy null:


const btn = document.querySelector(".button");
const styleComputed = window.getComputedStyle(textCnt, null);

console.log( styleComputed.getPropertyValue("height") );
console.log( styleComputed.width );
console.log( styleComputed['background-color'] );

Gdy sprawdzisz w konsoli wynik powyższego skryptu, zorientujesz się, że dane zwracane przez omawianą metodę różnią się od tego, co zostało podane w CSS.
I tak w stylach kolor przycisku ma #f15c5c, a zwracany jest rgb(166, 14, 14). Podobnie z rozmiarem czcionki. W CSS jest on zapisany w jednostce rem, a zwracany jest w px. W tym ostatnim przypadku żeby uzyskać rezultat w rem trzeba wynik przeliczyć przez zwrócony rozmiar dla elementu html.

Wartość style pobrana za pomocą getComputedStyle jest właściwością tylko do odczytu. Próba ustawienia za jej pomocą nowych stylów zakończy się błędem: getComputedStyle error

Mając teorię za sobą, poprawmy wcześniejszy przykład i usuńmy z niego style inline:


<div class="module">
    <h3 class="module-title">Przykładowa nazwa artykułu</h3>
    <div class="module-content"> <!-- usuneliśmy atrybut style -->
        Lorem ipsum dolor sit amet...
    </div>
    <button type="button" class="button module-button" id="testShowContent">Pokaż treść</button>
</div>

const btn = document.querySelector(".button");
const textCnt = btn.previousElementSibling;

btn.addEventListener("click", function() {
    btn.addEventListener("click", function() {
        const styleComputed = window.getComputedStyle(textCnt, null);

        if (styleComputed.display === "none") {
            textCnt.style.display = "inline-block";
        } else {
            textCnt.style.display = "none";
        }
    });
});

Przykładowa nazwa artykułu

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Soluta itaque doloremque reiciendis illo placeat officia voluptate, et sapiente, laboriosam tempore exercitationem velit quis quibusdam iste molestiae alias obcaecati ut natus!

Aby pobrać style dla pseudo elementu musimy skorzystać z drugiego parametru tej metody:


const module = document.querySelector('.module');
const styleComputed = window.getComputedStyle(textCnt, ':before');

console.log(styleComputed.backgroundColor);

classList

W powyższych przykładach ustawialiśmy właściwości css za pomocą JS. Niema co ukrywać - w dzisiejszych czasach starsze zasady tworzenia stron się nieco rozmywają. Jedna z takich zasad mówiła o oddzieleniu warstw od siebie. HTML to treść dokumentu, JS odpowiada za manipulowanie taką treścią i dodawanie interakcji. Za wygląd odpowiedzialny jest CSS.
Właśnie dlatego w wielu przypadkach ustawianie wyglądu powinno się odbywać za pomocą CSS - a dokładnie klas w css, a JS powinien tylko odpowiednio manipulować tymi klasami - dodawać je, odejmować itp. Dzięki temu jeżeli w przyszłości najdzie konieczność np. zmiany sposobu zmiany danego przycisku, zmienisz tylko odpowiednie klasy w CSS, a JS zostawisz w spokoju.

Aby zarządzać klasami css danego elementu użyjemy właściwości classList, która udostępnia nam kilka metod:

  • add("nazwa-klasy") - dodawanie klasy
  • remove("nazwa-klasy") - usuwanie klasy
  • toggle("nazwa-klasy") - przełączanie (jak nie ma to dodaje, jak jest to usuwa) klasy
  • contain("nazwa-klasy") - sprawdza czy element ma taką klasę

const btn = document.querySelector('.btn');


btn.classList.add('btn'); //dodaję klasę .btn
btn.classList.remove('btn'); //usuwam klasę .btn
btn.classList.toggle('btn'); //przełączam (dodaję lub usuwam) klasę .btn
btn.classList.contain('btn'); //sprawdzam czy dany element ma klasę .btn

className

Właściwość className zwraca nam jako tekst wszystkie klasy jakie posiada dany element:


const btn = document.querySelector('.btn');
console.log(btn.className); //btn btn-primary

W czasach gdy wsparcie dla classList było marginalne, była to główna właściwość, która pozwalała zarządzać klasami. Każdy taki manewr wymagał dodatkowego kodu:


const btn = document.querySelector('.btn');
const classText = "nazwaKlasy";

//add
btn.className += " "+classText;

//remove
const classText = classText;
const regPattern = new RegExp('(\\s|^)'+classText+'(\\s|$)');
btn.className = btn.className.replace(regPattern, '');

//contain
if (btn.className.indexOf('btn')!==-1) {
    console.log('Przycisk ma klasę btn');
}

//toggle
if (btn.className.indexOf('btn')!==-1) {
    btn.className += " "+classText;
} else {
    const regPattern = new RegExp('(\\s|^)'+classText+'(\\s|$)');
    btn.className = btn.className.replace(regPattern, '');
}

Ogólnie nie polecam stosować tej właściwości do manipulacji klasami, a tylko do ewentualnego odczytu tych klas