Css Selectores por UserAgent: Estilos específicos para cualquier versión de cualquier navegador en cualquier SO

Cómo declarar Css específico para cualquier versión de cualquier navegador discriminando también por sistema operativo. Y ya puestos ¿qué tal si el poder apuntar a dispositivos táctiles?

Css Selectores por UserAgent: Estilos específicos para cualquier versión de cualquier navegador en cualquier SO

Por Kseso ✎ 6

Css Selectores por UserAgentLejos quedan los días de la necesidad casi inexcusable de utilizar hacks css o comentarios condicionales para compensar las carencias o bugs de los navegadores. Especialmente los "recordados" ie6/ie7.

Necesidad venida a menos con la evolución y mejoras al soporte de Css y sus propiedades y valores y a la interpretación cuasi homogénea que hacen de las especificaciones sus versiones más actuales.

Sin embargo y pese a ello, de vez en cuando te topas con alguno de los bugs, unos más nuevos y otros ya veteranos, y es entonces cuando buscas y hechas de menos una forma de declarar algo de Css específico para un navegador en concreto.

Y ya puestos, seguro que agradecerías si, además de poderlo hacer para un navegador específicamente, pudieras limitar su aplicación a una versión concreta si fuese necesario. Y ya puestos a pedir, acotarlo a un Sistema Operativo. ¿Sí?

Pues acabas de encontrar tu regalo de navidades. Lo puedes hacer y de forma sencilla. Vamos con ello.

Selectores Css por User Agent

Para hacer posible todo lo prometido en la intro del post sería ideal que Css pudiera acceder a información fuera del documento Html, los datos que el navegador suministra al servidor para identificarse y conocida como user agent o agente de usuario.

Como Css no tiene acceso a esa parte, tenemos que apoyarnos en un lenguaje que sí lo haga y además que lo ponga accesible a Css y sus selectores. El indicado es javascript. Así que el primer paso es colocar el siguiente código en la página.

<script> var d0cum3n7e13m3n7 = document.documentElement; d0cum3n7e13m3n7.setAttribute('data-useragent', navigator.userAgent); d0cum3n7e13m3n7.setAttribute('data-platform', navigator.platform); d0cum3n7e13m3n7.className += ((!!('ontouchstart' in window) || !!('onmsgesturechange' in window))?' touch':''); </script>

Nota: Este código js ha sido modificado respecto al original por Furoya por las razones que expone en su comentario.

Este código js lo que hace es generar dentro de la etiqueta de apertura del html dos atributos, data-useragent y data-platform, con sus valores correspondientes.

Así, si accedes a la página con Firefox y windows, el resultado será algo como:

<html data-useragent="Mozilla/5.0 (Windows NT 6.0; rv:26.0) Gecko/20100101 Firefox/26.0" data-platform="Win32">

Para ie9 el resultante se parecerá a:

<html data-useragent="Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET4.0C; .NET CLR 3.0.30729)" data-platform="Win32">

Más interesante, podemos saber si es un Ipad, por ejemplo, por el valor de atributo data-platform:

data-useragent='Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10' data-platform='iPad'>

Selectores Css por User Agent

Ahora ya tenemos la información accesible por el Css. Sólo nos resta utilizar el selector apropiado. En este caso el selector de atributo, y más concretamente el que nos permite seleccionar por una parte del valor de atributo. Ya sea el que selecciona una cadena de texto [attr*='valor'] o el más selectivo que selecciona una cadena de texto "tal cual" entre espacios en blanco [attr~='valor'].

Así, si te topas con un bug en la versión 22 de Firefox, por ejemplo, sólo es necesario declarar el Css.

html[data-useragent*='Firefox/22.0'] .mielemento { /* Css específico */ }

Pero podemos ir un paso más allá, y discriminar por sistema operativo. Si en el caso anterior sólo se ve afectada la versión para windows, encadenamos selectores por atributos para incluir las dos variables:

html[data-useragent*='Firefox/22.0'][data-platform='Win32'] .mielemento { /* Css específico */ }

¿Que sólo necesitas apuntar a los Ipad, por ejemplo como en el último código html anterior? Sencillo. Sólo tienes que utilizar el data-platform='iPad':

html[data-platform='iPad'] mielemento { /* Css específico */ }

Pero no te vayas, aún hay más diversión.

Detección de dispositivos táctiles

Regresa al js del inicio. Verás que queda por comentar su última línea. La que añade la clase touch si es un dispositivo táctil.

Apoyándonos en ella podemos introducir Css específico para este tipo de dispositivos. Así, si tienes alguna regla para algún :hover, que recuerda en los táctiles no hay posibilidad de hacerlo, puedes reescribirla sólo para apuntar a ellos:

nav li { display: none; } nav:hover li { display: block; } /* Para los táctiles */ .touch nav li { display: block; }

Créditos y reconocimiento de autoría

Css Selectores por UserAgent Este artículo es deudor en su totalidad y está basado en el post publicado por @rogie en su blog: "CSS: User Agent Selectors".
Tanto el script como la denominación "user agent selector". Ve al original, que a lo mejor he cometido algún fallo o error en la interpretación de sus palabras.

Ramajero Argonauta, Enredique Amanuense de CSS.
#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Don Kseso Kseso

Comentarios: 6

  1. Muy práctico. Y no solamente para corregir "incongruencias", sino simplemente para dar formatos distintos al documento según la aplicación (azul y celeste para IE, rojo y anaranjado para Firefox, ...) que es otra opción para los diseñadores.
    También para poner mensajes según el navegador o sistema operativo. O según el idioma que tenga configurado el usuario, o avisarle si tiene las cookies activadas, o ...

    Las posibilidades son muchas, pero en realidad las dejo para los próximos comentarios en esta entrada. Porque aprovecho para hacer dos observaciones y después un aporte (si no es un abuso).

    En javascript se utilizan muchas variables para "pasarse" datos entre funciones. Y los nombres no suelen ser muy originales.
    El punto es que las 'var=' no pueden repetirse, porque la última reemplaza a la anterior, y si se va a usar más de un escript (que es muy común poner alguno para los menúes, otro para un slider de fotos, y así en más), hay que asegurarse de que no vayan a coincidir los nombres de distintas variables globales. En el ejemplo están llenando la 'var = b;' con la referencia al documento para después buscarle la plataforma para el navegador o el agente de usuario. Pero resulta que "b" es un nombre muuuuy común, y no estaría de más para quienes no se manejen muy fluidamente con el JS, usar una ugly variable, que se escribe a mano o se genera con algún programita, y que es más difícil que se vaya a repetir por casualidad. Son las mismas cadenas que se usan para no repetir id's (por ejemplo "QsG6J8M", "bGtNd9W", "VcXr5000"), y sólo hay que asegurarse que en nuestro escript sean exactamente iguales.

    Lo segundo que quería comentar es algo que ya pregunté hace un tiempo : ¿Entonces podemos publicar javascript?
    8D
    (por supuesto, si es para modificar o acceder al CSS)

    Por último, el aporte, que daría por afirmativa la respuesta a esa pregunta, o me van a eliminar el comentario.

    Resulta que el valor de 'navigator.userAgent' puede contener mucha y desprolija información (digo desprolija para extraerla con CSS según nuestras necesidades). A veces es necesario "ver" qué devuelve la máquina para usar el fragmento que sea el justo que precisamos para diferenciar un navegador de otro. Y lo mejor en esos casos es verlo antes de escribir nuestros estilos. Para eso existe en cada navegador una consola, pero como tampoco es indispensable a un diseñador conocerla, dejo una versión que muestra el "código fuente" (en verdad, el interpretado por el browser) en un mensaje de alerta. Aquí se puede leer claramente lo que queda escrito en los atributos donde hurga el CSS.

    <!DOCTYPE html>
    <html lang="es-ar">
    <head>
    <meta charset="utf-8" />
    <script type="text/javascript">
    var d0cum3n7e13m3n7 = document.documentElement;
    d0cum3n7e13m3n7.setAttribute('data-useragent', navigator.userAgent);
    d0cum3n7e13m3n7.setAttribute('data-platform', navigator.platform);
    d0cum3n7e13m3n7.className += ((!!('ontouchstart' in window) || !!('onmsgesturechange' in window))?' touch':'');

    alert(d0cum3n7e13m3n7.outerHTML);

    </script>
    </head>
    <body>
    </body>
    </html>


    Disculpen lo extenso del comentario, sufro de incontinencia gráfica y me aprovecho que en los blogs de los amigos me la aguantan.

    ResponderEliminar
    Respuestas
    1. ¿Entonces podemos publicar javascript? Furoya dixit.
      Creo que la pregunta sería otra:
      ¿Por qué el autor del blog no publica javascript u otros lenguajes?
      Y la pregunta la tienes justo en este post y en tu corrección (gracias):
      Porque no me apetece hablar sin saber de qué estoy hablando y contribuir con más burradas y sinsentidos a tantos como ya existen xD

      Pero por si quedan dudas, el teclado es vuestro y yo soy el chico de la limpieza reacio a ejercer y a trabajar pa´ná =P

      Con tu permiso, y también sin él, modifico el js del artículo con el tuyo.

      Y como curiosidad, la ventaja de la ignorancia es que me obliga a estrujar la neurona que me queda activa a estas alturas.
      Así que a falta de saber de eso de alert(d0cum3n7e13m3n7.outerHTML); así me las apañé para saber la salida de ese js

      html {
      background: blue;
      display: block;
      }
      html:before {
      content: '<html class="' attr(class) '" data-useragent="' attr(data-useragent) '" data-platform="' attr(data-platform) '">';
      display: block;
      position: relative;
      font-family: monospace;
      font-size: 1.5rem;
      color: #fff;
      margin: 1rem;
      padding: 1rem;
      }



      Sí, ya se que ahí están el inspector de código o el Firebug o equivalentes, pero eso no tiene gracia xD

      Eliminar
    2. Gracias a vos por tenerme en cuenta. Claro, lo de leer los valores en un 'content' es cierto, no se me había ocurrido.

      Eliminar
  2. Qué buena idea y qué bien la publiquen en español.
    Sólo 2 cosas:

    1. Si no quieres depender de JS para tener acceso a el User agent, pues los lenguajes de servidor también tienen acceso al UA string. Con PHP puedes usar $_SERVER['HTTP_USER_AGENT'] y para más datos puedes usar la función get_browser() más info en: http://cl1.php.net/get_browser (sólo debes tener PHP relativamente actualizado).

    2. Si vamos a usar JS y no queremos contaminar el entorno global con variables que se pueden pisar unas a otras, ejecutamos el Javascript dentro de una función anónima auto llamada, así no tenemos que recurrir a nombre de variables casi random, el resultado es algo así:



    (function (){
    var b = document.documentElement;
    b.setAttribute('data-useragent', navigator.userAgent);
    b.setAttribute('data-platform', navigator.platform);
    b.className += ((!!('ontouchstart' in window) || !!('onmsgesturechange' in window))?' touch':'');
    alert(b.outerHTML);
    })();


    ResponderEliminar
    Respuestas
    1. Bueno, justamente esto es lo que se quiere evitar, la contaminación de un blog CSS con tanto lenguaje de programación. La verdad es que me estoy arrepintiendo de preguntar, es la segunda vez que pasa esto y alguien que yo conozco me va a echar la culpa a mí por tirar la idea.

      Usando PHP o JS o Flash se puede hacer cualquier cosa sin depender de los estilos, pero la idea es darle un uso que justifique el CSS ya conocido por los que vienen a este blog ¿no?. Debería ser lo más sencillo y comprensible que se pueda, hasta que nos permita razonar cómo funciona siguiendo la sintaxis y que -quizá- se aplique a otros casos con un poco de investigación por parte de quien le ineterese empezar con programación.
      Uno típico que no quise mencionar es el 'input' que tenga por omisión la fecha del día. En CSS no existe y podría estar perfectamente; pero exponerlo en JS ya es mucho para este blog.
      Tal como explicar lo de las funciones (anónimas o no), y la forma de encapsularlas para que cualquier nombre de variable no salga de allí y contamine a otra función con una 'var' homógrafa.

      Volviendo un poco a lo de PHP, me gustaría resumir, para quien no lo usa, que es un lenguaje de programación de servidor, no funciona en el navegador "cliente"; es decir, que no ve directamente la información de la que justamente estamos hablando aquí sino que "se la pide", la sube al sitio donde está alojada la página, la procesa, reescribe el código fuente basado en los datos y lo vuelve a enviar al navegador. O más o menos así, seguramente en otros blogs sobre Hypertext Pre-processor lo van a explicar mejor.

      Por último, te agradecería que ayudes a que no me terminen echando de aquí también, Agustín, o voy a convertirme en un verdadero paria de la web y va a caer sobre tu conciencia.

      ;-)

      Gracias.

      Eliminar
  3. Magnífico este blog y este post me ha sido utilísimo.

    Me he suscrito, por supuesto.

    ResponderEliminar

EsCss RSS del Blog RSSS Comentarios Humans.txt ᛯ Diseno por Kseso SiteMap