Css Selectores por UserAgent: Estilos específicos para cualquier versión de cualquier navegador en cualquier SO 13.1.14
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
Lejos 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
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.
Kseso
the obCSServer ᛯ 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 Kseso
¿Entonces podemos publicar javascript? Furoya dixit.
ResponderEliminarCreo 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
Qué buena idea y qué bien la publiquen en español.
ResponderEliminarSó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);
})();
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.
EliminarUsando 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.
Gracias a vos por tenerme en cuenta. Claro, lo de leer los valores en un 'content' es cierto, no se me había ocurrido.
ResponderEliminarMagnífico este blog y este post me ha sido utilísimo.
ResponderEliminarMe he suscrito, por supuesto.