• Strona główna
  • Curriculum Vitae
  • O mnie
  • Mapa strony
  • Kontakt
Niebieski Pomarańczowy Zielony Różowy Fioletowy

Eksperymentalne własności w CSS3

Opublikowane 5 września 2010. Autor: Kamil Brenk. Wizyt: 1 234.

Kategorie: HTML5 & CSS3
Tematyka: CSS, CSS3, Minify CSS, mod_rewrite, optymalizacja serwisów, PHP, PHP PEAR, praktyczne skrypty, Protokół HTTP

wrz 05

W ostatnich czasie coraz więcej mówi się o nadchodzącym CSS3, który udostępnia web-developerom wiele nowych właściwości i funkcjonalności.

Niestety większość silników przeglądarek wprowadza swoje własne przedrostki dla tych własności, oznaczając je w ten sposób jako eksperymentalne. Mowa tutaj o -webkit-, -o-, -moz- czy -html-. W niniejszym wpisie opiszę sposób skracający pracę z tymi własnościami CSS3.

Kilka słów o vendor-prefixed

Vendor-prefixed to właśnie wspomniane przedrostki w eksperymentalnych własnościach CSS3. Zostają one dodane do takich wynalazków jak np. :

  • border-radius
  • transform
  • box-shadow
  • text-shadow
  • transition
  • text-stroke
  • text-fill-color
  • text-overflow
  • appearance

I własności tych z pewnością przybędzie, więc powyższa lista nie jest pełna. Przykładowo, aby dodać cień do tekstu należy wklepać następujący kod CSS:

1
2
3
4
5
-moz-text-shadow: 2px 2px 3px black;
-webkit-text-shadow: 2px 2px 3px black;
-o-text-shadow: 2px 2px 3px black;
-khtml-text-shadow: 2px 2px 3px black;
text-shadow: 2px 2px 3px black;

Prawda, że nie jest to zbyt efektywne? Niemniej jednak zadziała dla silników takich jak: WebKit, Opera, Mozilla, Konqueror. Ponadto własność ta musi zostać dodana także bez przedrostka, o czym możemy przeczytać tutaj.

Powyższy kod z różnymi przedrostkami jest również poprawny z punktu widzenia walidacji CSS3, więc nie musimy się tym martwić. Poza tym dostępnych jest więcej prefiksów dla różnych silników przeglądarek, dlatego polecam zapoznać się z całą listą vendor keywords (w powyższym przykładzie znajdują się tylko wybrane silniki, które wprowadzają własności CSS3).

Co jeśli musimy zmienić kolor cieniowania dla naszego tekstu? Niestety wiąże się to z koniecznością edycji pięciu własności, zamiast jednej. Postarajmy się więc temu zapobiec.

Style CSS generowane w PHP

Możemy zrobić następującą rzecz. Do naszego dokumentu dołączamy standardowy element LINK z następującym adresem do stylów CSS:

1
<link rel="stylesheet" type="text/css" href="style.php" media="all" />

Jak widać, odsyłamy przeglądarkę do pliku style.php, zamiast do dokumentu CSS. Niemniej jednak jest to prawidłowe i możemy tak postąpić (można również przy pomocy mod_rewrite przepisać adres, tak by wyglądał na style.css lub można również dołączać kod PHP bezpośrednio do CSS i pliki o rozszerzeniu CSS dodać do wykonywanych plików przez parser PHP).

Nasz przykładowy plik style.php może teraz wyglądać następująco:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
header('Content-Type: text/css; charset=UTF-8');
?>

@charset "utf-8";

h1 {
    margin: 0;
    padding: 0;
    font-weight: normal;
    color: #32639A;
    font-family: Georgia, "Times New Roman", Times, serif;
}

Co tutaj się dzieje? Najpierw otwieramy znacznik PHP i powiadamiamy przeglądarkę w nagłówku, że ma do czynienia z plikiem CSS (kodowanie znaków w UTF-8).

Potem możemy już dodawać normalne style CSS, jak powyżej dla elementu H1.

W powyższym dokumencie nie ma jak na razie niczego ciekawego i rozwiązującego nasze problemy. Czas więc się za to zabrać.

Generowanie własności z prefiksami

Aby skrócić sobie zabawę z wypisywaniem własności z vendor-prefixed dla każdego silnika przeglądarek z osobna, dopiszemy prostą funkcję, która tym się za nas zajmie.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * Add vendor-prefixed CSS3
 *
 * @param string    property name
 * @param string    property value
 *
 * @return string   property with vendor-prefixed CSS3
**/

function _exp($property, $value) {

    $css = null;

    // mozilla
    $css .= "-moz-$property: $value;\n";
   
    // webkit
    $css .= "-webkit-$property: $value;\n";
   
    // opera
    $css .= "-o-$property: $value;\n";
   
    // konquero
    $css .= "-khtml-$property: $value;\n";
   
    // non-vendor-prefixed CSS3
    $css .= "$property: $value;\n";
   
    return $css;

}

A później wystarczy tylko:

1
_exp('text-shadow', '2px 2px 3px black');

Czyli podsumowując, przykładowy dokument CSS może wyglądać następująco:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
header('Content-Type: text/css; charset=UTF-8');


/**
 * Add vendor-prefixed CSS3
 *
 * @param string    property name
 * @param string    property value
 *
 * @return string   property with vendor-prefixed CSS3
**/

function _exp($property, $value) {

    $css = null;

    // mozilla
    $css .= "-moz-$property: $value;\n";
   
    // webkit
    $css .= "-webkit-$property: $value;\n";
   
    // opera
    $css .= "-o-$property: $value;\n";
   
    // konquero
    $css .= "-khtml-$property: $value;\n";
   
    // non-vendor-prefixed CSS3
    $css .= "$property: $value;\n";
   
    return $css;

}

?>


@charset "utf-8";

h1 {
    margin: 0;
    padding: 0;
    font-weight: normal;
    color: #32639A;
    font-family: Georgia, "Times New Roman", Times, serif;
    <?= _exp('text-shadow', '2px 2px 3px black'); ?>
}

Natomiast po odpaleniu w przeglądarce zostanie wypluty poniższy kod CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@charset "utf-8";

h1 {
    margin: 0;
    padding: 0;
    font-weight: normal;
    color: #32639A;
    font-family: Georgia, "Times New Roman", Times, serif;
    -moz-text-shadow: 2px 2px 3px black;
    -webkit-text-shadow: 2px 2px 3px black;
    -o-text-shadow: 2px 2px 3px black;
    -khtml-text-shadow: 2px 2px 3px black;
    text-shadow: 2px 2px 3px black;
}

Wydaje mi się to bardzo użytecznym rozwiązaniem upraszczającym sporo niepotrzebnej roboty.

Epilog

Oczywiście do powyższego dokumentu CSS warto by dodać:

  • buforowanie wyniku, tak aby tylko raz wykonywać po stronie serwera powyższe polecenia PHP i odciążyć tym samym serwer z niepotrzebnych operacji,
  • przepisywanie linków na „przyjazne”, dzięki czemu nikt nie będzie krzywił miny na dokument CSS zapisany pod rozszerzeniem PHP,
  • można również dodać wykrywanie przeglądarki i serwować tylko prefiks dla odpalonego silnika – jednak nie wiem czy byłoby to opłacalne z punktu widzenia optymalizacji i należałoby uprzednio przetestować ten sposób.

Na zakończenie prosty przykład z buforowaniem:

style.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
header('Content-Type: text/css; charset=UTF-8');

// Include Cache_Lite from PEAR
require_once "Cache/Lite.php";

/**
 * Add vendor-prefixed CSS3
 *
 * @param string    property name
 * @param string    property value
 *
 * @return string   property with vendor-prefixed CSS3
**/

function _exp($property, $value) {

    $css = null;

    // mozilla
    $css .= "-moz-$property: $value;\n";
   
    // webkit
    $css .= "-webkit-$property: $value;\n";
   
    // opera
    $css .= "-o-$property: $value;\n";
   
    // konquero
    $css .= "-khtml-$property: $value;\n";
   
    // non-vendor-prefixed CSS3
    $css .= "$property: $value;\n";
   
    return $css;

}


// save css in cache
$options = array(
    'cacheDir' => 'temp/',
    'lifeTime' => 0
);

$cache = new Cache_Lite($options);


if ($data = $cache->get('css_style')) {

    echo $data;
   
} else {

    ob_start();
    include 'style.css';
    $data = ob_get_contents();
   
    $cache->save($data);
   
}

style.css

1
2
3
4
5
6
7
8
9
10
@charset "utf-8";

h1 {
    margin: 0;
    padding: 0;
    font-weight: normal;
    color: #32639A;
    font-family: Georgia, "Times New Roman", Times, serif;
    <?= _exp('text-shadow', '2px 2px 3px black'); ?>
}

Mam nadzieję, że powyższa technika komuś się przyda. Sam chyba zacznę z niej korzystać przy kolejnych projektach (w połączeniu z CSS Minify).

Podobne wpisy

  • Kompresja CSS
  • Boilerplate 2.0
  • Kompresja JavaScript
  • Pobieranie adresów URL z innej strony
  • PHP5. Zaawansowane programowanie

Komentarze (11)

  1. Tomasz Kowalczyk 5 września 2010

    Vendor prefixed może być całkiem istotnym postępem przeciwko dopisywaniu ciągle tych samych fragmentów tekstu – myślę, że to jedna z najistotniejszych informacji jakie wyniosłem z tego wpisu. ;]

  2. Michal Wachowski 6 września 2010

    Wszystko pięknie ładnie – ale jest jeden zonk:

    1
    2
    3
    border-bottom-left-radius: 5px;
    -webkit-border-radius-bottomleft: 5px;
    -moz-border-radius-bottomleft: 5px;

    I tutaj cały misterny skrypt padł.

  3. Kamil Brenk 6 września 2010

    @Michał: faktycznie, nie pomyślałem o tym border-radius (zawsze tylko bezmyślnie kopiuję kod dla tej własności z wykorzystaniem border-radius.com).

    Niemniej jednak wystarczy drobna poprawka w powyższej funkcji uwzględniająca ten wyjątek i po sprawie :-)

  4. Alan Gabriel Bem 8 września 2010

    W świecie railsów furorę robią takie narzędzia jak LESS albo SASS w których to o czym piszesz – i wiele więcej – już istnieje.

  5. css3.pl 11 września 2010

    Tak jak wyżej zauważył kolega, nie wszystkie właściwości CSS3 są pisane jednakowo we wszystkich obsługujących je przeglądarkach. Po drugie, opisywany przez ciebie „text-shadow” akurat w ogóle nie potrzebuje prefiksu, ponieważ już od dawna jest obsługiwany po prostu jako „text-shadow” w Operze, Firefoksie, Chrome i Safari.
    Mimo to wpis ciekawy.

  6. Kamil Brenk 11 września 2010

    Macie racje Panowie, powyższy skrypt nie jest idealny. Żeby wszystkie te nowe własności obsługiwać w prawidłowy sposób należałoby napracować się znacznie bardziej, ja podałem tylko skrócone rozwiązanie.

    1) Można by dodać własności, które wymagają przedrostków.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    // properties with vendor-prefixed
    $allow_property = array(
        'animation', 'animation-delay', 'animation-direction', 'animation-duration', 'animation-iteration-count', 'animation-name', 'animation-play-state', 'animation-timing-function',
        'appearance',
        'backface-visibility',
        'baseline-shift',
        'binding',
        'bookmark-label', 'bookmark-level', 'bookmark-target',
        'background-break', 'background-clip', 'background-origin', 'background-size',
        'border-image', 'border-image-outset', 'border-image-repeat', 'border-image-slice', 'border-image-source', 'border-image-width', 'border-length',
        'border-radius', 'border-bottom-left-radius', 'border-bottom-right-radius', 'border-top-left-radius', 'border-top-right-radius',
        'box-align', 'box-decoration-break', 'box-direction', 'box-flex', 'box-flex-group', 'box-lines', 'box-ordinal-group', 'box-orient', 'box-pack', 'box-shadow', 'box-sizing',
        'color-profile',
        'column-break-after', 'column-break-before', 'column-count', 'column-fill', 'column-gap', 'column-rule', 'column-rule-color', 'column-rule-style', 'column-rule-width', 'column-span', 'column-width', 'columns',
        'crop',
        'display-model', 'display-role',
        'dominant-baseline',
        'drop-initial-after-adjust', 'drop-initial-after-align', 'drop-initial-before-adjust', 'drop-initial-before-align', 'drop-initial-size', 'drop-initial-value',
        'fit', 'fit-position',
        'float-offset',
        'font-size-adjust', 'font-stretch',
        'grid-columns', 'grid-rows',
        'hanging-punctuation',
        'hyphenate-after', 'hyphenate-before', 'hyphenate-character', 'hyphenate-lines', 'hyphenate-resource',
        'hyphens',
        'icon',
        'image-orientation', 'image-resolution',
        'inline-box-align',
        'line-stacking', 'line-stacking-ruby', 'line-stacking-shift', 'line-stacking-strategy',
        'mark', 'mark-after', 'mark-before', 'marks',
        'marquee-direction', 'marquee-play-count', 'marquee-speed', 'marquee-style',
        'move-to',
        'nav-down', 'nav-index', 'nav-left', 'nav-right', 'nav-up',
        'outline-offset',
        'page-policy',
        'perspective', 'perspective-origin',
        'phonemes',
        'presentation-level',
        'punctuation-trim',
        'rendering-intent',
        'resize',
        'rest', 'rest-after', 'rest-before',
        'rotation', 'rotation-point',
        'ruby-align', 'ruby-overhang', 'ruby-position', 'ruby-span',
        'string-set',
        'tab-side',
        'target', 'target-name', 'target-new', 'target-position',
        'text-emphasis', 'text-justify', 'text-outline', 'text-replace',
        'transform', 'transform-origin', 'transform-style',
        'transition', 'transition-delay', 'transition-duration', 'transition-property', 'transition-timing-function',
        'voice-balance', 'voice-duration', 'voice-pitch', 'voice-pitch-range', 'voice-rate', 'voice-stress', 'voice-volume',
        'white-space-collapse'
    );

    if (!in_array($property, $allow_property)) {
        return "$property: $value;\n";
    }

    :D

    2) Należałoby dodać obsługę wyjątków w pisowni niektórych własności, przykładowo:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    switch ($property) {
       
        case 'border-bottom-left-radius':
        case 'border-bottom-right-radius':
        case 'border-top-left-radius':
        case 'border-top-right-radius':
            $css .= _borderXradius($property, $value);
        break;
       
        default:
            $css .= addVendorPrefixed($property, $value);
        break;
       
    }

    Kod musiałby być dużo bardziej złożony i na bieżąco aktualizowany, bowiem przeglądarki wciąż implementują kolejne własności i funkcjonalności z CSS3.

    Dużo roboty, a jeszcze więcej trudności z samodzielnym zapamiętaniem by samemu stosować w praktyce. Trochę nieciekawie to wygląda – kolejne komplikacje, jakby nie można było tego zrobić normalnie i zgodnie ze specyfikacją.

    Stąd próba usystematyzowania i ułatwienia z mojej strony, choć niekoniecznie udana – trza by dokończyć robotę na porządnie. Poza tym sam kod pewnie rozrastałby się w dość szybkim tempie, więc dobrze by było przemyśleć zastosowaną architekturę rozwiązania na nowo – powyższy sposób nie jest zbyt piękny :-)

  7. Kamil Brenk 11 września 2010

    @Alan: dopiero teraz czytam Twój komentarz, ponieważ już po raz drugi trafiłeś do spamu i nie dostałem powiadomienia o nowym komentarzu – nawet nie wiem dlaczego tak się dzieje, ale to tylko przy komentarzach od Ciebie.

    Co do LESS czy innych tego typu, słyszałem i całkiem fajna sprawa. Nie sądziłem jednak, że mają już zaimplementowaną i tą funkcjonalność, o której pisałem w tym wpisie – dzięki za informację! :-)

  8. Kamil Brenk 8 listopada 2010

    https://github.com/codler/jQuery-Css3-Finalize
    a tutaj wtyczka dla jQuery, dzięki której możemy w skrótowy sposób używać nowych własności CSS3 w jQuery :-)

  9. zzz 12 lutego 2011

    Ciekawostka, nowa strona główna Interii już używa css3, oraz warunkowych stylów dla IE.

  10. Alan Gabriel Bem 12 lutego 2011

    Warunkowe style są passe :)

    http://paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/

  11. Kamil Brenk 13 lutego 2011

    @zzz: nie tylko Interia, ale większość nowych stron, w tym w niewielkim stopniu nawet Google (HTML5 & CSS3).

    Także i ja w większości swoich projektów używam HTML3 & CSS3, najczęściej w ogóle nie zważając na IE6. W końcu to od nas – webdeveloperów – zależy kiedy stare i nieaktualne przeglądarki znikną z rynku i tym samym ułatwimy sobie życie.



Dodaj komentarz

XHTML: Możesz użyć następujących tagów
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Kamil Brenk Blog

PHP, JavaScript, SQL, HTML

  • Informacje o blogu

    Kamil Brenk

    Blog o tworzeniu aplikacji na potrzeby sieci Web.

    Praktyczne przykłady, porady i sztuczki. PHP, SQL, AJAX, JavaScript, HTML i pochodne.

    Kanał RSS

    • Najnowsze
    • Komentarze
    • Popularne
    • Gramatyka w HTML i CSS
    • PHP kontra Microsoft Office, part I
    • Cross-Domain JavaScript: CORS
    • Wysyłanie wiadomości SMS w PHP
    • Boilerplate 2.0
    • Własne selektory w jQuery
    • Kamil Brenk: @Michał:1) jak już otrzymam dyplom to zrobię serię o...
    • Michal Wachowski: Po pierwsze - tyle czekania i tylko to? A bu! :) Po drugie -...
    • Kamil Brenk: @CapaciousCore: języki kompilowane są szybsze niż...
    • CapaciousCore: @Kamil Brenk wiem, że komentarze i post nie są uber świeże....
    • Kamil Brenk: @CapaciousCore: post i komentarze napisane ponad rok temu;...
    • CapaciousCore: Przebrnąłem przez te wszystkie komentarze i mam trochę...
    • Kamil Brenk: @arhiman: dzięki za komentarz :)A to dziwne co piszesz, bo...
    • Przyszłość PHP
    • Niestandardowe czcionki na stronie
    • Gramatyka w PHP, część 1
    • Umowa i zaliczka dla freelancera
    • Projekt aplikacji po stronie klienta
    • Własny mechanizm Feed
    • jQuery.extends dla PHP
  • Szukajka
    Wpisz co chcesz wyszukać na stronie…
  • Kategorie
    • Apache
    • Freelancer
    • Front-end Development
    • HTML5 & CSS3
    • Inne
    • JavaScript
    • Książki
    • PHP
    • Po godzinach
    • Pozycjonowanie
    • Protokół HTTP
    • SQL
    • Wyrażenia regularne
  • Moje serwisy
    • Testy zawodowe
    • Miłość, uczucia i seks
  • Czytane blogi
    • Wojciech Sznapka
    • Wojciech Soczyński
    • Michał Wachowski
    • Tomasz Kowalczyk
    • JavaScript po polsku | Code42
  • Archiwum
    • Luty 2012
    • Listopad 2011
    • Październik 2011
    • Wrzesień 2011
    • Sierpień 2011
    • Lipiec 2011
    • Maj 2011
    • Kwiecień 2011
    • Marzec 2011
    • Luty 2011
    • Styczeń 2011
    • Grudzień 2010
    • Listopad 2010
    • Październik 2010
    • Wrzesień 2010
    • Sierpień 2010
    • Lipiec 2010
    • Czerwiec 2010
    • Maj 2010
    • Kwiecień 2010
    • Marzec 2010
    • Luty 2010
    • Styczeń 2010
  • Strona główna
  • Curriculum Vitae
  • O mnie
  • Mapa strony
  • Kontakt

Kamil Brenk © 2010. All rights reserved.

Designed by FTL Wordpress Themes brought to you by Smashing Magazine.

Do góry ∧