Cuando se trata de renderizar en DOM de otra persona, no puedes escribir ingenuamente HTML y CSS como lo harías para tu propia aplicación web autónoma. Debe pensar cuidadosamente sobre cómo los códigos preexistentes de CSS y JavaScript pueden afectar su aplicación.

Antes de comenzar a escribir cualquier HTML o CSS, tendrá que tomar una decisión importante con respecto a la apariencia de su aplicación. ¿Desea que su aplicación se vea igual en todos lados? ¿O desea que la aplicación herede el aspecto y la apariencia nativa de la página en la que está alojado? Su respuesta tendrá un profundo efecto en su estrategia para renderizar su aplicación.

Una cosa es constante: en algún nivel, estarás practicando lo que llamamos representación defensiva. A la defensiva, nos referimos a tomar medidas para generar HTML y CSS que minimicen el impacto de la página principal en su aplicación. Cuanto menos quieras que tu widget sea impactado por la página principal, más pasos tendrás que seguir. Estos pasos pueden ser tan pequeños como el espacio de nombres de su HTML y CSS para reducir los conflictos de nombres, o sobreespecificar sus reglas de CSS para que tengan prioridad sobre las reglas de la página principal. Para los widgets que desean una inmunidad completa desde la página principal, también podría significar que se debe publicar el widget en un DOM completamente separado, incrustado en un iframe.

Nos centraremos en renderizar HTML y CSS que vivan en el mismo DOM que la página del editor. Para los widgets que pretenden ofrecer cierto nivel de personalización, esta puede ser la solución más flexible para los editores, ya que el editor puede orientar fácilmente sus elementos y personalizarlos según sus preferencias.

Desafortunadamente, esta también es la desventaja. El editor podría tener, sin saberlo, reglas de CSS y / o código JavaScript que apuntan inadvertidamente a su widget y causan estragos.

Veremos una serie de maneras de proteger el HTML y CSS de su aplicación del código del editor. Primero, aprenderá sobre los espacios de nombres HTML y CSS. Luego, aprenderá sobre la especificidad de CSS y cómo los estilos de la página principal pueden anular la suya.

Finalmente, aprenderá técnicas para anular los estilos principales de la página, al sobreespecificar su CSS y abusar de la palabra clave importante. Primero, espacios de nombres.

Espacios de nombres

Todas las identificaciones de DOM, clases, atributos de data- * y selectores de CSS coincidentes han sido prefijados con stork-. ¿El propósito? Para reducir la probabilidad de que esos atributos entren en conflicto con la página principal.

Considera la siguiente situación. Tu widget tiene un nivel superior

elemento que actúa como un contenedor. Hace esto estableciendo un ancho y alto explícitos, delimitando efectivamente el área ocupada por su widget. Has dado esto
un nombre de clase sencillo, contenedor, que coincide con una regla de estilo en el CSS que lo acompaña:

...

Esto podría ser perfectamente apropiado para una aplicación habitual de permanecer en el hogar, pero para una aplicación de terceros, es un completo no-no. ¿La razón? Tal nombre genérico de clase tiene una buena probabilidad de ser utilizado por la página padre. Si introduce esta regla de estilo, puede anular una regla de estilo existente establecida por el editor y arruinar el diseño de su sitio. O, por otro lado, su regla puede anular la suya y cambiar el tamaño de su widget inadvertidamente.

¿La solución? Prefijo todos sus nombres de clase (y otros atributos) con un identificador exclusivo de su aplicación: un espacio de nombres. En el caso del widget Stork, el marcado anterior debe modificarse para que se vea así:

...

La idea es que el espacio de nombres de su código de JavaScript para que no declare objetos globales que entran en conflicto con el código que se ejecuta en la página principal. Se extiende a cada pieza de HTML que inserte en la página: ID, clases, atributos data- *, nombres de formularios, etc.

El espaciado de nombres de HTML y CSS es obligatorio para cualquier aplicación de terceros que se muestre directamente en la página del editor. Esto no es solo necesario para evitar reglas CSS contradictorias; también es concebible que la página principal tenga JavaScript que consulte el DOM para elementos cuyas propiedades de identificación puedan coincidir con las suyas. Sea riguroso en el espacio de nombres de todo lo que pone en el DOM.

Especificidad de CSS

Es importante tener en cuenta que, aunque útil, el espacio de nombres de su HTML y CSS solo previene los casos en que el editor utiliza estilos o consultas que hacen referencia a los atributos con el mismo nombre que el suyo. Desafortunadamente, su widget aún puede entrar en conflicto con los estilos definidos por la página principal, incluso si su CSS utiliza ID, nombres de clase y atributos que no hacen referencia directa a sus elementos. Esto se debe a que el navegador pesa algunas reglas de CSS y puede tener prioridad sobre las reglas aparentemente no relacionadas que pueda definir. Este fenómeno se conoce como especificidad de CSS, y deberá comprenderlo antes de poder representar de manera segura los elementos en la página del editor.

Volvamos al ejemplo de contenedor de la sección anterior sobre espacios de nombres. Supongamos que el HTML del editor tiene un DIV de nivel superior que envuelve todo su contenido, con un ID de página:

...
...

Además, digamos que la página tiene el siguiente CSS, donde la primera regla la define el editor y la segunda regla, que se dirige a cigüeña-contenedor, es agregada por su script de terceros:

/* Publisher */#page div {background-color: green;}/* Camera Stork */.stork-container {background-color: blue;}

Ahora, ¿qué color tendrá .stork-container? La respuesta puede sorprenderte y aterrarte: verde. En este ejemplo simple, la regla del editor (#page div) tiene prioridad sobre la regla de clase de su aplicación de terceros (.stork-container). Esto sucede porque el navegador pesa las reglas que contienen ID más altas que aquellas que se dirigen a clases o atributos.

Prioridades de reglas de CSS

La especificación W3C CSS describe cómo los navegadores deben priorizar diferentes tipos de reglas. Aquí hay una lista de estos tipos de reglas, ordenadas desde la más alta a la más baja:

  1. Estilos en línea (estilo = "...")
  2. IDs
  3. Clases, atributos y pseudo-clases (: focus,: hover)
  4. Elementos (div, span, etc.) y pseudo-elementos (: antes,: después)

De acuerdo con este cuadro, los estilos en línea se pesan por encima de todos los tipos de reglas posteriores: ID, clases y elementos. Esto continúa lógicamente en la lista, con los ID priorizados más altos que las clases y los elementos, y así sucesivamente. Hay una excepción a esta lista: las propiedades etiquetadas con la palabra clave! Important toman la más alta prioridad. Pero tenga en cuenta que la palabra clave! Importante afecta a una sola propiedad dentro de una regla, no a la regla completa.

¿Qué sucede cuando tienes múltiples reglas de CSS del mismo peso, cada una de las cuales podría afectar el mismo elemento? Echemos un vistazo a un ejemplo:

Eat your vegetables!

¿Cuál crees que es el color del tramo? La respuesta nuevamente podría ser sorprendente: amarillo. Aunque estas reglas se basan principalmente en clases, la segunda regla (.storkcontainer span) se considera más específica que la primera regla, y la tercera regla (.stork-container .stork-msg) más específica que la segunda. ¿Como funciona esto?

Los estilos en línea son rey

En términos de especificidad de CSS, eso es. Si recuerda algo anterior en este capítulo, mencionamos que los estilos en línea tienen el beneficio de que raramente entran en conflicto con la página principal. Ahora está claro por qué: se priorizan sobre cualquier otro tipo de regla de CSS regular (excepto aquellos con la palabra clave! Important). Si está escribiendo un widget particularmente simple, puede que no sea una mala idea usar estilos en línea; evitará la mayoría de los conflictos de especificidad de CSS.

El navegador utiliza un sistema de puntuación simple para determinar qué regla tiene prioridad. Para una regla dada, cada selector que compone esa regla vale un cierto valor. Esos valores se suman para crear una puntuación de especificidad. Cuando varias reglas afectan al mismo elemento, el navegador compara el puntaje de especificidad de cada regla y la regla con el puntaje más alto tiene prioridad. En el caso de un empate, la regla que se definió por última vez gana. Atributos de estilo en línea: 1000; IDs: 100; clases, pseudo-clases y atributos: 10, elementos y pseudo-elementos: 1.

Por lo tanto, volviendo a nuestro ejemplo anterior, a esas reglas de CSS se les habrían asignado las siguientes puntuaciones, con la regla de mayor puntuación priorizada por el navegador: notará rápidamente que estos no son números comunes. Un puntaje de especificidad es en realidad una tupla de la forma (a, b, c, d), con un ser más valioso que b, b es más valioso que c, y así sucesivamente. Esto significa que un estilo causado por un único atributo de estilo en línea (1, 0, 0, 0) tiene una especificidad mayor que una regla con cien selectores de ID (0, 100, 0, 0).

  • .stork-container (selector de clase 0,0,1,0-one)
  • .stork-container span (0,0,1,1-one selector de clase, selector de un elemento)
  • .stork-container .stork-msg (Selectores de clase 0,0,2,0-dos)

En este punto, debe tener una buena idea de cómo funciona la especificidad CSS, y por qué el navegador prioriza algunas reglas sobre otras. A continuación, utilizará este conocimiento, mientras exploramos algunos enfoques para escribir CSS que se destacan por los estilos conflictivos de los editores.

Sobreespecificación de CSS

El primer y más simple enfoque para escribir CSS que no entre en conflicto con la página del editor es sobreespecificar sus reglas. Esto significa declarar selectores adicionales para aumentar la especificidad de sus reglas, de modo que cuando el navegador compara sus reglas con las de la página principal, es probable que obtengan una puntuación más alta y se prioricen.

Veamos esto en la práctica. Considere este ejemplo revisado del contenedor de artilugios Stork, que ahora cuenta con dos elementos contenedores, cada uno con una ID única:

Mikon E90 Digital SLR

"/>

$ 599

4.3 / 5.0 • 176 Evaluaciones

El CSS que acompaña este HTML podría verse así:

#stork-main #stork-container { ... }#stork-main #stork-container .stork-product { ... }#stork-main #stork-container .stork-price { ... }

Al especificar de forma redundante ambos identificadores de contenedor como selectores principales de todas sus reglas de CSS, está otorgando efectivamente a cada una de sus reglas de CSS un puntaje mínimo de especificidad de (0,2,0,0). Después, la regla #page genérica del editor anterior no entrará en conflicto con su widget, ya que solo usa una única ID. Tampoco existirán conflictos entre las reglas puramente basadas en clases o elementos, ya que se trata de una clase completa de ponderación de CSS debajo de las ID. Aunque, para fines de selección, es completamente innecesario especificar un segundo ID para sus reglas, aquí funciona como un dispositivo efectivo para aumentar la especificidad.

Conserva tu cordura con un preprocesador de CSS

Escribir un CSS sobre especificado puede ser una verdadera traba: tienes que reescribir constantemente los mismos ID una y otra vez para cada una de tus reglas de CSS. Puede remediar esto utilizando un preprocesador CSS, que amplía el lenguaje CSS con características adicionales como la capacidad de declarar jerarquías anidadas de reglas. Por ejemplo, usando el preprocesador LESS CSS, podría escribir el ejemplo anterior así:

#stork-main {#stork-container {.stork-product { ... }.stork-price { ... }}}

Actualmente, hay disponibles varios preprocesadores CSS populares, todos los cuales tienen diferentes conjuntos de características. Entre los más populares están MENOS,Hablar con descaro a, y Aguja.

Por otro lado, este ejemplo requiere que su widget use contenedores de nivel superior con ID, lo que no será práctico para los widgets que se pueden renderizar varias veces en la misma página. Además, todavía no es a prueba de balas: un editor podría seguir su ejemplo y sobreespecificar sus propias reglas de CSS, lo que provocaría el mismo problema que tenía antes.

Pero este es un escenario poco probable, especialmente dado que ha especificado dos identificaciones redundantes en cada una de las reglas. Alternativamente, puede usar uno, pero esto, por supuesto, será más vulnerable. La realidad es que la mayoría de los editores usan reglas de CSS sanas, y la sobreespecificación de sus reglas como esta será compatible con la mayoría de ellas.

La sobre especificación de CSS no se combina con herramientas de calidad de código

Si lleva a sobreespecificar su CSS de esta manera, puede encontrar un enemigo poco probable: herramientas que evalúan la calidad de su código CSS, como CSS Lint, Google Page Speed ​​y YSlow de Yahoo. Estas herramientas indicarán que está creando selectores CSS redundantes, y le aconsejarán que elimine dichos selectores para reducir el tamaño del archivo y mejorar el rendimiento del CSS de los navegadores. Desafortunadamente, estas herramientas no están programadas con scripts de terceros en mente, y no evalúan la utilidad de sobreespecificar CSS. Los beneficios de la sobreespeculación para aplicaciones de terceros superarán el tamaño de archivo adicional y el minúsculo rendimiento alcanzado.

Abusar! Importante

Si crees que la sobreespecificación de tu CSS con ID o selectores de clase adicionales no es suficiente, puedes desglosar la opción nuclear: la palabra clave important. Las propiedades dentro de una regla de CSS que tienen la palabra clave importante se priorizan como las más importantes, incluso por encima de los estilos en línea. Esto se debe a que la palabra clave! Important se diseñó para ofrecer a los usuarios del navegador una manera segura de anular los estilos de "autor" (editor), en el caso de los complementos del navegador o los estilos específicos del sitio. Puede abusar! Importante al usarlo en todas sus propiedades de CSS, priorizándolas de manera efectiva sobre todas las demás reglas.

A continuación, le indicamos cómo puede usar la palabra clave! Importante en una regla de CSS única:

.stork-price {font-size: 11px !important;color: #888 !important;text-decoration: none !important;display: block !important;}

Dado que es por propiedad, la palabra clave! Important necesita ser repetida de esta manera, lo que puede convertirse en un arrastre sobre una hoja de estilo larga y compleja. Pero, a cambio, obtienes un conjunto sólido de hojas de estilo que es muy poco probable que se restablezcan en la página del editor.

Todavía es concebible que el editor, a su vez, pueda utilizar elementos importantes para orientar sus elementos y establecer sus propios estilos, en cuyo caso es probable que se orienten deliberadamente a sus elementos para la personalización. Por un lado, eso puede ser frustrante si tratas de mantener un aspecto y una sensación consistentes. Pero, si ha decidido permitir a los editores personalizar su widget, este es probablemente el comportamiento deseado.

Una cosa debe estar clara: compartir el DOM con el editor puede hacer que sea particularmente difícil renderizar un widget de estilo consistente. Aunque puede tomar medidas para sobreespecificar sus reglas de CSS para reducir la probabilidad de conflictos, siempre es posible que el editor oriente sus elementos con sus reglas, ya sea accidental o deliberadamente.

Pero si compartir el DOM con el editor es lo que está causando tanto dolor, ¿es posible sacar el widget del DOM? Por qué, sí, sí puedes.

Resumen

Para una aplicación de JavaScript de terceros, inyectar HTML y CSS en la página del editor requiere más atención que si añadiera el marcado a un entorno "seguro". Debe asegurarse de que al enviar HTML a la página, no esté ralentizando la página con una operación de bloqueo. También debe tener en cuenta que su secuencia de comandos puede incluirse varias veces en la misma página, y debe representar varias instancias con gracia. Además, debe elegir un método óptimo para insertar CSS en la página del editor, ya sea al subrayar todos sus estilos, agregar elementos de enlace o incorporar reglas de CSS en su JavaScript.

Pero solo obtener HTML y CSS en la página no es suficiente. Debe reconocer que los elementos que introduce en el DOM pueden entrar en conflicto con la página principal. También debe considerar cómo sus estilos pueden entrar en conflicto con los estilos existentes definidos por el editor. Puede usar una serie de técnicas para reducir el impacto de los estilos principales en su widget: sobreespecificando sus reglas CSS o presentando su contenido detrás de un iframe, ya sea un iframe sin src o uno que contenga un documento HTML externo.

¿Qué técnicas usas cuando produces CSS y HTML para terceros? ¿Alguna vez vuelves a caer! ¿Importante? Háganos saber en los comentarios.

Imagen / miniatura destacada, imagen de defensa a través de Shutterstock.