Tworzenie wykresów za pomocą CSS

29 września 2015
1 gwiadka2 gwiazdki3 gwiazdki4 gwiazdki5 gwiazdek

Dane można przedstawić wizualnie na wiele sposobów: na wykresach słupkowych, liniowych, punktowych, przebiegu w czasie i wielu innych, nie wspominając już o możliwościach dostępnych na stronach internetowych. W artykule tym przedstawiam techniki prezentacji danych za pomocą kaskadowych arkuszy stylów. Ale przed pokazaniem konkretnych przykładów chciałbym krótko omówić podstawowe cele projektowe.

Wytyczne dotyczące tworzenia wykresów

Każdy wykres przeznaczony do publikacji w internecie powinien spełniać trzy następujące wymogi:

  1. Dostępność: prezentowane na wykresie dane powinny być w jakiś sposób widoczne dla każdego użytkownika. Może to być nawet zwykła wiejąca nudą tabela (nieciekawa prezentacja jest lepsza niż żadna).
  2. Łatwość tworzenia: nie należy niepotrzebnie komplikować sobie procedur tworzenia wykresu i w szczególności powinno się unikać technik, które w przyszłości mogą zmusić nas do dodatkowej pracy.
  3. Wydajność: użytkownicy nie mogą długo czekać na pobranie zasobów i pojawienie się elementów na ekranie monitora.

Oczywiście zestaw celów może być różny w zależności od typu wykresu. Na przykład, kwestia wydajności w przypadku statycznego wykresu słupkowego ma całkiem inną wagę niż w przypadku interaktywnej mapy.

Implementacja wykresów w CSS

Wykres słupkowy w CSS można stworzyć na kilka sposobów. Na pierwszy ogień do zapisania danych weźmiemy listę definicji:

<dl>
  <dt>Tytuł wykresu</dt>
  <dd class="percentage">
    <span class="text">
      Wielkość 1: 20%
    </span>
  </dd>
  <dd class="percentage">
    <span class="text">
      Wielkość 2: 50%
    </span>
  </dd>
  <dd class="percentage">
    <span class="text">
      Wielkość 3: 30%
    </span>
  </dd>
</dl>

Zawartość tekstową elementów dd znajdującą się w elementach span przesuniemy w lewo za pomocą pozycjonowania bezwzględnego.

Słupki reprezentujące dane utworzymy za pomocą pseudoelementów. W tym celu dodamy do kodu HTML klasy w rodzaju .percentage-20, a następnie ustawimy szerokość dla związanych z nimi pseudoelementów:

.percentage:after {
  content: "";
  display: block;
  background-color: #3d9970;
}
.percentage-20:after {
  width: 20%;
}
.percentage-30:after {
  width: 30%;
}

Klas tych nie powinniśmy jednak wpisywać ręcznie, ponieważ dane mogą się zmienić. Dlatego do utworzenia wszystkich potrzebnych nam klas skorzystamy z pętli Sass:


@for $i from 1 through 100 {
  .percentage-#{$i}:after {
    $value: ($i * 1%);
    width: $value;
  }
}

To rozwiązanie jest trochę słabe, ponieważ zakłada utworzenie bardzo dużej liczby klas, których prawdopodobnie nigdy nie użyjemy, ale w razie potrzeby zawsze możemy posprzątać kod przed przekazaniem go do produkcji za pomocą specjalnych narzędzi.

Teraz możemy przypisywać automatycznie wygenerowane klasy elementom .percentage:

<dl>
  <dt>Tytuł wykresu</dt>
  <dd class="percentage percentage-7">
    <span class="text">
      IE 11: 7%
    </span>
  </dd>
  <dd class="percentage percentage-20">
    <span class="text">
      Chrome: 20%
    </span>
  </dd>
  <dd class="percentage percentage-2">
    <span class="text">
      Android 4.4: 2%
    </span>
  </dd>
</dl>

Na koniec dodamy regułę definiującą powtarzalny gradient liniowy w tle elementów .percentage, aby poprawić czytelność danych:


.percentage {
  background: repeating-linear-gradient(
    to right,
    #ddd,
    #ddd 1px,
    #fff 1px,
    #fff 5%
  );
}
Wykres słupkowy przedstawiający udział przeglądarek w rynku

Jest to w miarę prosta technika, choć nie mogę pozbyć się wrażenia, że tego rodzaju informacje zawsze powinno się definiować w tabeli. Choć nie jestem pewien co do możliwości stylizowania tabel w ten sposób, nie znaczy to automatycznie, że tak się nie da. Na przykład Eric Meyer napisał artykuł o tej technice i pokazał w nim, jak pozycjonować elementy tabeli, aby zmusić je do przyjęcia formy wykresu. Oto kod HTML tabeli zaczerpnięty z tej publikacji:

<table id="q-graph">
    <caption>Quarterly Results</caption>
    <thead>
        <tr>
         <th></th>
            <th class="sent">Invoiced</th>
            <th class="paid">Collected</th>
        </tr>
    </thead>
    <tbody>
        <tr class="qtr" id="q1">
        <th scope="row">Q1</th>
        <td class="sent bar"><p>$18,450.00</p></td>
        <td class="paid bar"><p>$16,500.00</p></td>
    </tr>
        <tr class="qtr" id="q2">
        <th scope="row">Q2</th>
        <td class="sent bar"><p>$34,340.72</p></td>
        <td class="paid bar"><p>$32,340.72</p></td>
    </tr>
    <tr class="qtr" id="q3">
        <th scope="row">Q3</th>
        <td class="sent bar"><p>$43,145.52</p></td>
        <td class="paid bar"><p>$32,225.52</p></td>
    </tr>
    <tr class="qtr" id="q4">
        <th scope="row">Q4</th>
        <td class="sent bar"><p>$18,415.96</p></td>
        <td class="paid bar"><p>$32,425.00</p></td>
    </tr>
    </tbody>
</table>

W odróżnieniu od mojego przykładu, w którym wykorzystałem automatycznie generowane za pomocą Sass klasy definiujące szerokość słupków wykresu, Meyer zastosował w elementach td style śródliniowe, których wartości są obliczane na serwerze lub za pomocą JavaScriptu.

Poniżej znajduje się moja kopia oryginalnego przykładu Meyera z nieco ulepszonym formatowaniem wizualnym:

Przykład wykresu słupkowego Erica Meyera

Bardzo podoba mi się, że każdy wiersz tabeli ma nagłówek Q1, Q2 itd. To rozwiązanie wygląda znacznie lepiej i porządniej niż moja lista definicji. Elementy tabeli łatwo się pozycjonuje, a poza tym w razie kłopotów z obsługą CSS na ekranie pojawi się przynajmniej standardowa tabela.

Wadą tej techniki jest konieczność bezwzględnego pozycjonowania wszystkich wierszy tabeli, aby ustawić je w rzędzie — gdyby trzeba było dodać nowe dane, nie wystarczyłoby tylko wprowadzić zmian w kodzie HTML. To oznacza, że nasza przyszłość z takim wykresem może nie być usłana różami.

Wykresy punktowe

Do prezentowania informacji nie trzeba jednak koniecznie używać tabel. Dotyczy to na przykład wykresów punktowych, które są bardzo małe i umieszcza się je obok linii tekstu, aby zapewnić szybki przegląd opisywanych informacji. Metodę tę opisał Wilson Miner, który dodatkowo zadbał o zapewnienie zawczasu odpowiedniej dostępności informacji:

<figure>
<ul class="sparklist">
  <li>
    <a href="http://www.example.com/fruits/apples/">Apples</a>
    <span class="sparkline">
      <span class="index"><span class="count" style="height: 27%;">(60,</span> </span>
      <span class="index"><span class="count" style="height: 97%;">220,</span> </span>
      <span class="index"><span class="count" style="height: 62%;">140,</span> </span>
      <span class="index"><span class="count" style="height: 35%;">80,</span> </span>
  </li>
</ul>
<figcaption>Fruits eaten in the last 14 days by type</figcaption>
</figure>

Trochę zmieniłem kod Minera, ponieważ wg mnie powinien on znajdować się w elemencie figure. W portalu MDN znalazłem następujące informacje:

Element figure zazwyczaj reprezentuje obraz, ilustrację, diagram, fragment kodu lub schemat opisany w tekście głównym, który jednak można przenieść do innego dokumentu lub dodatku bez zaburzenia głównego nurtu treści.

Wg mnie to o wiele bardziej sensowne rozwiązanie niż używanie elementu ul. W każdym razie tak to wygląda bez zastosowania arkuszy stylów:

Wykres pozbawiony formatowania CSS

Bardzo dostępne! Teraz możemy dodać arkusze stylów dla elementu wykresu (sparkline) i przesunąć go na prawą stronę odnośnika za pomocą wartości inline-block. Oczywiście do ustawiania wysokości słupków moglibyśmy użyć generatora klas Sass, z którego korzystaliśmy już wcześniej. Ale na razie pozostawimy te style bezpośrednio w kodzie HTML:

Przykłady wykresów punktowych

Najedź kursorem na dowolną pozycję listy, aby zobaczyć powiększoną wersję wykresu. Może technika ta nie wprowadza niczego nowego w kwestii analizy danych, ale pokazuje, że nie musimy ograniczać się tylko do jednego rodzaju reprezentacji wykresów. Łatwość z jaką można zmieniać te wizualizacje jest wielką zaletą metod opartych na prostym kodzie HTML i CSS.

Wykresy kołowe w CSS

Lea Verou napisała świetny artykuł na temat tworzenia wykresów kołowych. Jedną z wymienionych przez nią możliwości jest wykorzystanie pseudoelementów pokrywających koło i manipulowanie nimi za pomocą przekształcenia transform: rotate().

Inną możliwością jest wykorzystanie technologii SVG. Ma ona wiele zalet, które opiszę kiedyś w innym artykule.

Gdyby przeglądarki obsługiwały funkcję conic-gradient(), to byłaby to bardzo kusząca opcja. Na razie niestety nie jest z tym najlepiej, choć Lea Verou ma wypełniacz, który działa po prostu doskonale. Poniżej znajduje się przykładowy wykres kołowy przedstawiający wyniki pewnej sondy przeprowadzonej w portalu CSS-Tricks:

See the Pen Pie Chart with Conic Gradient by Łukasz Piwko (@shebangpl) on CodePen.

Problemy z formatowaniem wykresów w CSS

  • Jeśli element ma zdefiniowane tło za pomocą własności background, to prawdopodobnie będzie ono niewidoczne na wydruku. Jedynym wyjątkiem jest sytuacja, gdy zostanie użyta deklaracja -webkit-print-color-adjust: exact; w przeglądarkach WebKit.
  • Utrudniona kontrola nad projektem: bezwzględnie pozycjonowane wiersze tabeli mogą w przyszłości przysporzyć kłopotów.
  • Zapewnienie zgodności kodu z wszystkimi przeglądarkami jest czasami pracochłonne, a przetestowanie obsługi każdej własności CSS w każdym urządzeniu może być bardzo trudne.
  • Nie da się definiować stylów śródliniowych dla pseudoelementów, co znacznie komplikuje sprawę, jeśli do ich formatowania chce się użyć JavaScriptu.
  • Za pomocą CSS można zrobić wszystko, ale tworząc wykresy liniowe przy użyciu wyłącznie CSS, należy zastanowić się, jaki to będzie miało wpływ na resztę kodu.

Podsumowanie

Techniki tworzenia wykresów i grafów bazujące wyłącznie na CSS i HTML są do pewnego stopnia skuteczne i w wielu przypadkach powinny być najlepszym wyborem. Uważam jednak, że warto też znać inne rozwiązania reprezentacji danych.

Dodatkowe źródła

Autor: Robin Rendle

Źródło: https://css-tricks.com/making-charts-with-css/

Tłumaczenie: Łukasz Piwko

Treść tej strony dostępna jest na zasadach licencji CC BY-SA 3.0

Dyskusja

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *