Advertisement
  1. Web Design
  2. HTML & CSS

Cómo agregar variables a tus archivos CSS

Scroll to top
Read Time: 12 min

() translation by (you can also view the original English article)

Probemos algo diferente en nettuts+ hoy. Cualquier diseñador que haya trabajado con archivos CSS grandes estará de acuerdo en que su principal debilidad es su incapacidad para usar variables. En este artículo, aprenderemos cómo implementar variables usando PHP y el mod rewrite URL de Apache.


Prefacio

Esta técnica es algo simple. Le pediremos a Apache que redirija cualquier hoja de estilo a un script PHP específico. Esta secuencia de comandos abrirá la hoja de estilo y la leerá línea por línea para encontrar y reemplazar cualquier variable definida por el usuario. Finalmente, el contenido analizado se mostrará como CSS puro; Los navegadores no notarán la diferencia. Para cerrar este tutorial, también veremos cómo almacenar en caché el resultado procesado para evitar el uso innecesario de la CPU.

Tenga en cuenta que se esperan algunos conocimientos básicos de PHP (OOP), Apache y HTTP.

Requisitos:

  • Apache con Rewrite mod activado
  • PHP 5

Paso 1 - Crear el Proyecto

Primero creamos nuestra estructura de proyecto simple. Agregue un archivo index.html a la raíz de su proyecto.

1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
<html xmlns="http://www.w3.org/1999/xhtml">
3
<head>
4
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
    <title>Variables in CSS Files... It's possible!</title>
6
    <link href="css/styles.css" rel="stylesheet" type="text/css" />
7
</head>
8
<body>
9
    <h1>Variables in Stylesheets</h1>
10
    <p>It's possible!</p>
11
    <p>With PHP and Apache URL Rewrite Mod</p>
12
</body>
13
</html>

Ahora, cree un archivo CSS con las siguientes variables y colóquelo en una carpeta "css"

1
$font: arial, sans-serif;
2
$main-color: #3D7169; $secondary-color: #000;
3
4
h1 {
5
    font: 200% $font;
6
    color: $main-color;
7
}
8
p { 
9
    background: $secondary-color;
10
    color: $main-color;
11
    font-family: $font;
12
    padding: 10px;
13
}

Finalmente, cree un archivo PHP en blanco llamado enhanced_css.php y un archivo .htaccess en blanco. Este último archivo anula la configuración predeterminada del servidor y se aplica a la carpeta y sus subcarpetas.

Ahora nuestro proyecto debería verse así:


Paso 2 - Redirigir los archivos CSS a un script PHP

Queremos redirigir cualquier URL con una extensión CSS a nuestro script PHP. El servidor Apache nos permite hacer esto utilizando el mod de reescritura de URL.
Primero, asegúrese de que los módulos "rewrite_module" estén activos en su servidor. Vaya y encuentre el archivo httpd.conf su carpeta de Apache. Edítalo y busca esta línea:

1
LoadModule rewrite_module modules/mod_rewrite.so

Si es necesario, elimine el comentario eliminando el “#” que se adjunta, y reinicie Apache para asegurarse de que sus ajustes de configuración estén activos.

Ahora, edite su archivo .htaccess y agregue las siguientes líneas.

1
RewriteEngine on
2
RewriteRule ^(.*\.css)$ enhanced_css.php?css=$0

Guardalo. Como se mencionó anteriormente, las líneas anteriores le piden a Apache que capture todas las URL con la extensión .css y las redirija a "enhanced_css.php". La ruta del archivo CSS original se pasa como un parámetro 'css'.

Por ejemplo:

1
/css/styles.css 

Será redirigido a:

1
enhanced_css.php?css=/css/styles.css

Nota:

Algunas soluciones de alojamiento no permiten que sus configuraciones sean anuladas por las de los usuarios. Si es así, los enlaces a las hojas de estilo en el código HTML deben reemplazarse manualmente.

En tales casos, tendrá que reemplazar:

1
<link href="css/styles.css" rel="stylesheet" type="text/css" />

con:

1
<link href="enhanced_css?css=css/styles.css" rel="stylesheet" type="text/css" />

Paso 3 - Analizar el archivo CSS con PHP

Ya que los archivos CSS son redirigidos a nuestro script PHP, construyamos una clase llamada "Enhancedcss" para leerlos, buscar y reemplazar variables, luego mostrar los contenidos como CSS puro. Se instanciará nuestra clase al pasar $_GET['css'] al constructor. Recuerde la redirección de.htaccess. $_GET contiene la ruta a la hoja de estilo actual.

1
if (isset($_GET['css'])) {
2
    $css = new EnhancedCss($_GET['css']);    
3
    $css->display();
4
}

La implementación básica de la clase se compone de cuatro métodos. Más adelante, añadiremos un método de caché.

1
class EnhancedCss {
2
    public $values;
3
    public $cssFile;
4
    
5
    public function __construct($cssFile) {
6
        // check if the css file exists

7
    }
8
    
9
    private function parse() {
10
        // open the css file and throw every line to 

11
        // findAndReplaceVars method

12
    }
13
    
14
    private function findAndReplaceVars($line) {
15
        // find the variable definitions, store the values,

16
        // replace the variable by their defined values.

17
    }
18
    
19
    public function display() {
20
        // display the new parsed content        

21
    }
22
}

El constructor

Nada sexy aquí. Verificamos si existe el archivo CSS solicitado. Si no, el script devuelve un error de http 404. La ruta del archivo CSS se mantiene en la propiedad $this->cssFile para calcular el nombre del archivo de caché más adelante.

1
public function __construct($cssFile) {
2
    if (!file_exists($cssFile)) {
3
        header('HTTP/1.0 404 Not Found');
4
        exit;
5
    }
6
    $this->cssFile = $cssFile;
7
}

El Método Parse

Este método abre el archivo CSS y lo lee línea por línea.

1
private function parse() {
2
    $content = '';
3
    $lines = file($this->cssFile);
4
    foreach($lines as $line) { 
5
        $content .= $this->findAndReplaceVars($line); 
6
    }
7
    return $content;
8
}

La función file se utiliza aquí. Puede ser útil porque abre un archivo y devuelve el contenido como una matriz de líneas. Cada línea se lanza al findAndReplaceVars que procesa las variables. El contenido analizado se devuelve.

El método FindAndReplace

Este método es el principal caballo de batalla de nuestra clase. Encuentra las definiciones de variables, almacena sus valores en una matriz. Cuando se encuentra una variable y si su valor existe, se reemplaza por el valor.

1
private function findAndReplaceVars($line) {
2
    preg_match_all('/\s*\\$([A-Za-z1-9_\-]+)(\s*:\s*(.*?);)?\s*/', $line, $vars); 
3
    $found     = $vars[0];
4
    $varNames  = $vars[1];
5
    $varValues = $vars[3];
6
    $count     = count($found);    
7
                    
8
    for($i = 0; $i < $count; $i++) {
9
        $varName  = trim($varNames[$i]);
10
        $varValue = trim($varValues[$i]);            
11
        if ($varValue) {
12
            $this->values[$varName] = $this->findAndReplaceVars($varValue);
13
        } else if (isset($this->values[$varName])) { 
14
            $line = preg_replace('/\\$'.$varName.'(\W|\z)/', $this->values[$varName].'\\1', $line);
15
        }
16
    }
17
    $line = str_replace($found, '', $line);
18
    return $line;
19
}

Un montón de código aquí. Vamos a revisarlo en detalle.

1
private function findAndReplaceVars($line) {
2
    preg_match_all('/\s*\\$([A-Za-z1-9_\-]+)(\s*:\s*(.*?);)?\s*/', $line, $vars);

Aquí, aplicamos una expresión regular a la línea actual. Esta expresión coincide y extrae patrones como $variable:$value (y algunas variantes) o $variable en la línea actual. No voy a ir más lejos aquí. Las expresiones regulares son un tema complejo que merece un tutorial propio. La función Preg_match_all devuelve todas las coincidencias.

Por ejemplo, la tercera línea del archivo CSS de nuestro proyecto -

1
$main-color: #3D7169; $secondary-color: #000;

- devolverá esta matriz:

1
$vars => Array 
2
(
3
    [0] => Array
4
        (
5
            [0] => $main-color: #3D7169;

6
            [1] => $secondary-color: #000;

7
        )
8
9
    [1] => Array
10
        (
11
            [0] => main-color
12
            [1] => secondary-color
13
        )
14
15
    [2] => Array
16
        (
17
            [0] =>  : #3D7169;

18
            [1] =>  : #000;

19
        )
20
21
    [3] => Array
22
        (
23
            [0] =>  #3D7169

24
            [1] =>  #000

25
        )
26
)

Suponemos que $vars[0] contiene la coincidencia completa, $vars[1] contiene los nombres de las variables y $vars[3] contiene los valores. Vamos a organizar la matriz para que quede más claro.

1
$found     = $vars[0];
2
$varNames  = $vars[1];
3
$varValues = $vars[3];

Ahora es cristal.

1
$found => Array
2
        (
3
            [0] => $main-color: #3D7169;

4
            [1] => $secondary-color: #000;

5
        )
6
$varNames => Array
7
        (            
8
            [0] => main-color
9
            [1] => secondary-color
10
        )
11
 $varValues => Array
12
       (
13
           [0] =>  #3D7169

14
           [1] =>  #000

15
       )

Contamos cuántas variables se han encontrado en la línea actual.

1
    $count = count($found);

De esta manera podemos pasar por cada entrada de nuestra matriz de variables. Para aclarar las cosas, establecemos algunas nuevas variables para manejar el nombre y el valor.

1
for($i = 0; $i < $count; $i++) {
2
    $varName  = trim($varNames[$i]);
3
    $varValue = trim($varValues[$i]);            
4
5
    // ...

6
}

Definiciones de Variables

Si $varValue no está vacío, estamos frente a una definición variable. Así que tenemos que almacenar este valor en la propiedad $this->values.

1
if ($varValue) {
2
    $this->values[$varName] = $this->findAndReplaceVars($varValue);
3
} else if ...

Tenga en cuenta que volvemos a pasar el valor de la variable en el método findAndReplaceVars. De esta manera, también se procesarán otras variables potenciales.
Los valores se almacenan en la matriz $this->values ​​con el nombre de la variable como la clave. Al final de la secuencia de comandos, la matriz $this->values se ve así.

1
Array
2
(
3
    [font] => arial, sans-serif
4
    [main-color] => #3D7169

5
    [secondary-color] => #000

6
)

Aplicaciones de variables

Si $varValue está vacío, estamos frente a una aplicación variable. Verificamos si esta variable existe en la matriz de valores. Si lo hace, reemplazamos el nombre de la variable por su valor.

1
} else if (isset($this->values[$varName])) { 
2
    $line = preg_replace('/\\$'.$varName.'(\W|\z)/', $this->values[$varName].'\\1', $line);
3
}

Este reemplazo puede parecer anormalmente complicado. En realidad no, este reemplazo se encarga de reemplazar la $variable solo si va seguida de un no carácter (\W) o un final de línea (\z).

Finalmente, eliminamos toda la coincidencia para mantener la hoja de estilo limpia y válida. Se devuelve la línea procesada.

1
    $line = str_replace($found, '', $line);
2
    return $line;
3
}

El método de visualización

Este método muestra la hoja de estilo analizada. Para ser servido en el navegador como contenido CSS, el encabezado se establece en el tipo de contenido text/css.

1
public function display() {        
2
    header('Content-type: text/css'); 
3
    echo $this->parse();
4
}

Paso 4 - Guarda en caché el resultado

En este punto, todo está funcionando perfectamente. Sin embargo, la operación puede consumir mucho CPU cuando se usa con sitios web más grandes.

Después de todo, no necesitamos analizar los archivos CSS cada vez que el navegador lo necesita. El proceso solo debe ejecutarse la primera vez para crear el caché, o si el archivo CSS original se ha modificado desde la última operación de almacenamiento en caché. De lo contrario, el resultado renderizado previamente puede ser reutilizado. Entonces, agreguemos una solución de caché a nuestro script.

Agregue una nueva carpeta llamada caché al proyecto. Si es necesario, otorgue a esta carpeta el derecho de ser escrito aplicando un chmod 777. Ahora nuestro proyecto debería tener este aspecto:

El método Cache

Hay que añadir un nuevo método. Su función será:

  • leer el archivo de caché si existe.
  • Crear y almacena los resultados renderizados.
  • actualizar el archivo caché existente si el archivo CSS ha sido modificado.

Toda la lógica es manejada por el siguiente método:

1
private function cache($content = false) {
2
    $cacheFile = "cache/".urlencode($this->cssFile);
3
    if (file_exists($cacheFile) && filemtime($cacheFile) > filemtime($this->cssFile)) {
4
        return file_get_contents($cacheFile);
5
    } else if ($content) {
6
        file_put_contents($cacheFile, $content);
7
    }
8
    return $content;
9
}

Vamos a explicar este código. El nombre del archivo de caché se calcula a partir del nombre del archivo CSS original previamente guardado en la propiedad $this->cssFile. Finalmente, usamos la función urlencode.

1
$cacheFile = "cache/".urlencode($this->cssFile);

De esa manera un archivo CSS como

1
/css/styles.css

será cacheado como

1
/cache/css%2Fstyles.css

Necesitamos verificar si el archivo de caché ya existe, (file_exists) y si es así, verificar si su fecha de creación no es anterior a la fecha de modificación (filemtime) del archivo CSS.

1
if (file_exists($cacheFile) && filemtime($cacheFile) > filemtime($this->cssFile)) {
2
    return file_get_contents($cacheFile);

De lo contrario, creamos/recreamos el archivo cache.

1
} else if ($content) {
2
    file_put_contents($cacheFile, $content);
3
}

Ahora el resto de la clase debe lidiar con este nuevo método. Dos métodos necesitan ser modificados.

1
private function parse() {
2
    if (!$content = $this->cache()) {
3
        $lines = file($this->cssFile);
4
        foreach($lines as $line) { 
5
            $content .= $this->findAndReplaceVars($line); 
6
        }
7
    }
8
    return $content;
9
}

El método de análisis ahora comprueba el caché antes de ejecutar todo el proceso. Si no hay caché disponible, se analiza el archivo CSS, de lo contrario se devuelve el contenido almacenado en caché.

1
public function display() {
2
    header("Content-type: text/css"); 
3
    echo $this->cache($this->parse());
4
}

Finalmente, el método muestra el contenido correcto (nuevo o en caché) proporcionado por el método de almacenamiento en caché.

Cache del Navegador

Por razones de seguridad (sesiones, contenidos dinámicos), los navegadores no mantienen los resultados de PHP en su caché. Un archivo CSS real hubiera sido
cacheado pero no el resultado de nuestro script. Tenemos que lidiar con el navegador para emular el comportamiento de un archivo CSS real. Vamos a añadir algunas líneas al constructor.

1
public function __construct($cssFile) {
2
    if (!file_exists($cssFile)) {
3
        header('HTTP/1.0 404 Not Found');
4
        exit;
5
    }
6
7
    // Deals with the Browser cache

8
    $modified = filemtime($cssFile);
9
    header('Last-Modified: '.gmdate("D, d M Y H:i:s", $modified).' GMT');
10
  
11
    if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
12
        if (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $modified) {
13
            header('HTTP/1.1 304 Not Modified');
14
            exit();
15
        }
16
    }
17
18
    $this->cssFile = $cssFile;
19
}

Copiamos la última fecha de modificación del archivo CSS original a nuestro resultado en el encabezado.
Básicamente, los navegadores y servidores intercambian los encabezados antes de servir los datos.
Cuando el navegador tiene una copia de una página en su caché, envía una solicitud HTTP_IF_MODIFIED_SINCE al servidor
con la fecha dada previamente por el header('Last-Modified', ...) el día en que se almacenó en caché. Si las fechas coinciden, el contenido
está actualizado y no necesita ser recargado; por lo que enviamos una respuesta 304 Not Modified y salimos del script.

Una forma más corta sería simplemente agregar header('Cache-Control: max-age=3600'); al archivo. El contenido será cacheado
1 hora (3600 segundos) por cualquier navegador.


Conclusión

¡Hecho! Ahora puede comprobar una de sus hojas de estilo en su servidor. Por ejemplo, http://localhost/myproject/css/styles.css

1
$font: arial, sans-serif;
2
$main-color: #3D7169; $secondary-color: #000;
3
4
h1 {
5
    font: 200% $font;
6
    color: $main-color;
7
}
8
p { 
9
    background: $secondary-color;
10
    color: $main-color;
11
    font-family: $font;
12
    padding: 10px;
13
}

Se convierte en:

1
h1 {
2
    font: 200% arial, sans-serif;
3
    color: #3D7169;
4
}
5
p { 
6
    background: #000;
7
    color: #3D7169;
8
    font-family: arial, sans-serif;
9
    padding: 10px;
10
}

Espero que disfrutes este tutorial.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.