Quando se trata de renderização no DOM de outra pessoa, você não pode escrever ingenuamente HTML e CSS como você faria para seu próprio aplicativo da Web autocontido. Você precisa pensar cuidadosamente sobre como o código CSS e JavaScript preexistente pode afetar seu aplicativo.

Antes de começar a escrever qualquer HTML ou CSS, você terá que tomar uma decisão importante em relação à aparência da sua aplicação. Você quer que seu aplicativo seja o mesmo em todos os lugares? Ou você deseja que o aplicativo herde a aparência nativa da página em que está hospedado? Sua resposta terá um efeito profundo na sua estratégia de renderização do seu aplicativo.

Uma coisa é constante: em algum nível, você estará praticando o que chamamos de renderização defensiva. Por defensiva, queremos dizer tomar medidas para produzir HTML e CSS que minimizem o impacto da página principal em seu aplicativo. Quanto menos você quiser que seu widget seja impactado pela página principal, mais etapas você terá que realizar. Essas etapas podem ser tão pequenas quanto o namespacing de seu HTML e CSS para reduzir conflitos de nome ou especificar em excesso suas regras de CSS para que elas tenham prioridade sobre as regras da página principal. Para widgets que desejam imunidade total da página principal, isso também pode significar veicular seu widget em um DOM completamente separado, incorporado em um iframe.

Vamos nos concentrar na renderização de HTML e CSS que residam no mesmo DOM que a página do editor. Para widgets que visam oferecer algum nível de personalização, essa pode ser a solução mais flexível para editores, já que o editor pode facilmente segmentar seus elementos e adaptá-los às suas preferências.

Infelizmente, esta é também a desvantagem. O editor poderia inadvertidamente ter regras CSS e / ou código JavaScript que inadvertidamente direcionam seu widget e causam estragos.

Examinaremos várias maneiras de proteger o HTML e o CSS do seu aplicativo do código do editor. Primeiro, você aprenderá sobre namespaces HTML e CSS. Em seguida, você aprenderá sobre a especificidade do CSS e como os estilos da página pai podem substituir os seus.

Finalmente, você aprenderá técnicas para anular os estilos pai da página, superespecificando seu CSS e abusando da importante palavra-chave. Primeiro, namespaces.

Namespaces

Todos os IDs DOM, classes, data- * attributes e seletores CSS correspondentes foram prefixados com stork-. O objetivo? Para reduzir a probabilidade desses atributos conflitarem com a página principal.

Considere a seguinte situação. Seu widget tem um nível superior

elemento que age como um contêiner. Ele faz isso definindo uma largura e altura explícitas, limitando efetivamente a área ocupada pelo seu widget. Você deu isso
um nome de classe simples, container, que corresponde a uma regra de estilo em seu CSS acompanhante:

...

Isso pode ser perfeitamente apropriado para um aplicativo regular que fica em casa, mas para um aplicativo de terceiros, é um completo não-não. O motivo? Esse nome de classe genérico tem uma boa chance de já estar sendo usado pela página pai. Se você introduzir essa regra de estilo, poderá substituir uma regra de estilo existente implementada pelo editor e arruinar o layout do site. Ou, por outro lado, a regra deles pode sobrepor a sua e redimensionar o widget inadvertidamente.

A solução? Prefixando todos os nomes de classe (e outros atributos) com um identificador exclusivo para seu aplicativo - um namespace. No caso do widget Stork, a marcação anterior deve ser alterada para ficar assim:

...

A idéia é que você nomeie seu código JavaScript para que você não declare objetos globais que entram em conflito com o código em execução na página pai. Ele se estende a cada parte do HTML que você insere na página: IDs, classes, atributos data- *, nomes de formulários e assim por diante.

O namespace HTML e CSS é obrigatório para qualquer aplicativo de terceiros que renderize diretamente para a página do editor. Isso não é necessário apenas para evitar regras CSS conflitantes; Também é possível que a página pai tenha JavaScript que esteja consultando o DOM para elementos cujas propriedades de identificação possam corresponder às suas. Seja rigoroso em namespacing tudo o que você colocar no DOM.

Especificidade CSS

É importante observar que, apesar de útil, o namespacing de seu HTML e CSS apenas evita casos em que o editor está usando estilos ou consultas que fazem referência a atributos com o mesmo nome que o seu. Infelizmente, seu widget ainda pode entrar em conflito com os estilos definidos pela página pai, mesmo que o CSS use IDs, nomes de classe e atributos que não fazem referência direta a seus elementos. Isso ocorre porque algumas regras de CSS são mais pesadas pelo navegador e podem ter precedência sobre regras aparentemente não relacionadas que você possa definir. Esse fenômeno é chamado de especificidade de CSS e você precisará entendê-lo antes de poder renderizar elementos com segurança na página do editor.

Vamos voltar ao exemplo do contêiner da seção anterior sobre namespaces. Suponha que o HTML do editor tenha um DIV de nível superior que envolva todo o conteúdo, com um ID de página:

...
...

Além disso, digamos que a página tenha o seguinte CSS, onde a primeira regra é definida pelo editor, e a segunda regra, segmentação stork-container, é adicionada por seu script de terceiros:

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

Agora, que cor terá o container .stork? A resposta pode chocar e assustar você: verde. Neste exemplo simples, a regra do editor (#page div) tem prioridade sobre a regra de classe do seu aplicativo de terceiros (.stork-container). Isso acontece porque o navegador pesa regras que contêm IDs maiores do que aquelas que têm como alvo classes ou atributos.

Prioridades de regras CSS

A especificação CSS do W3C descreve como os navegadores devem priorizar diferentes tipos de regras. Aqui está uma lista desses tipos de regras, ordenadas da maior prioridade para a mais baixa:

  1. Estilos Inline (style = ”…”)
  2. IDs
  3. Classes, atributos e pseudo-classes (: focus,: hover)
  4. Elementos (div, span e assim por diante) e pseudoelementos (: before,: after)

De acordo com este gráfico, os estilos sequenciais são pesados ​​acima de todos os tipos de regras subseqüentes: IDs, classes e elementos. Isso continua logicamente na lista, com IDs priorizados acima de classes e elementos, e assim por diante. Há uma exceção a essa lista: as propriedades marcadas com a palavra-chave! Importante têm a maior prioridade. Mas note que a palavra-chave! Importante afeta uma única propriedade dentro de uma regra, não a regra inteira.

O que acontece quando você tem várias regras CSS com o mesmo peso, cada uma das quais poderia afetar o mesmo elemento? Vamos dar uma olhada em um exemplo:

Eat your vegetables!

O que você acha que é a cor do vão? A resposta novamente pode ser surpreendente: amarela. Embora essas regras sejam todas baseadas principalmente em classes, a segunda regra (extensão .storkcontainer) é considerada mais específica que a primeira regra, e a terceira regra (.stork-container .stork-msg) é mais específica que a segunda. Como é que isso funciona?

Estilos inline são rei

Em termos de especificidade CSS, isto é. Se você se lembrar do início deste capítulo, mencionamos que os estilos inline têm o benefício de raramente conflitar com a página pai. Agora está claro o porquê: eles são priorizados sobre todos os outros tipos de regra de CSS regular (excluindo aqueles com a palavra-chave! Importante). Se você está escrevendo um widget particularmente simples, pode não ser uma má idéia usar estilos in-line; você evitará a maioria dos conflitos de especificidade CSS.

O navegador usa um sistema de pontuação simples para determinar qual regra tem prioridade. Para uma determinada regra, cada seletor que compõe essa regra vale um determinado valor. Esses valores são somados para criar uma pontuação de especificidade. Quando várias regras afetam o mesmo elemento, o navegador compara o escore de especificidade de cada regra e a regra com a pontuação mais alta tem prioridade. No caso de empate, a regra que foi definida pela última vez vence. Atributos de estilo inline: 1000; IDs: 100; classes, pseudo-classes e atributos: 10, elementos e pseudo-elementos: 1.

Portanto, olhando para o nosso exemplo anterior, essas regras de CSS teriam as seguintes pontuações, com a regra de pontuação mais alta sendo priorizada pelo navegador: você notará rapidamente que esses números não são comuns. Uma pontuação de especificidade é, na verdade, uma tupla da forma (a, b, c, d), com um valor mais valioso que b, sendo b mais valioso que c e assim por diante. Isso significa que um estilo causado por um único atributo de estilo in-line (1, 0, 0, 0) tem maior especificidade que uma regra com cem seletores de ID (0, 100, 0, 0).

  • .stork-container (0,0,1,0 - seletor de uma classe)
  • extensão de contêiner-palete (0,0,1,1 - um seletor de classe, um seletor de elemento)
  • .stork-container .stork-msg (0,0,2,0 — dois seletores de classe)

Neste ponto, você deve ter um bom controle sobre como a especificidade CSS funciona e por que o navegador prioriza algumas regras sobre outras. Em seguida, você usará esse conhecimento, à medida que exploramos algumas abordagens para a criação de CSS que se destaca em relação a estilos de editor conflitantes.

Superespecificando CSS

A primeira e mais simples abordagem para escrever CSS que não entra em conflito com a página do editor é superespecificar suas regras. Isso significa declarar seletores adicionais para aumentar a especificidade de suas regras, de modo que, quando o navegador compara suas regras com as da página pai, é provável que elas pontuem mais alto e sejam priorizadas.

Vamos ver isso na prática. Considere este exemplo revisado do contêiner de widget Stork, agora com dois elementos de contêiner, cada um com um ID exclusivo:

Mikon E90 Digital SLR

"/>

US $ 599

4.3 / 5.0 • 176 Revisões

O CSS que acompanha esse HTML poderia ficar assim:

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

Ao especificar de forma redundante os IDs dos contêineres como seletores pais de todas as suas regras CSS, você está atribuindo a cada uma de suas regras CSS uma pontuação mínima de especificidade de (0,2,0,0). Posteriormente, a regra #page genérica do editor de antes não entrará mais em conflito com seu widget, pois ele usa apenas um único ID. Nenhuma das regras puramente baseadas em classes ou elementos entrará em conflito, porque elas são uma classe de peso CSS inteira abaixo de ID s. Mesmo que, para fins de seleção, seja completamente desnecessário especificar um segundo ID para suas regras, aqui ele funciona como um dispositivo eficaz para aumentar a especificidade.

Preserve sua sanidade com um pré-processador CSS

Escrever CSS superespecificado pode ser um empecilho real: você tem que reescrever constantemente os mesmos IDs repetidamente para cada uma de suas regras CSS. Você pode remediar isso usando um pré-processador de CSS, que estende a linguagem CSS com recursos adicionais, como a capacidade de declarar hierarquias aninhadas de regras. Por exemplo, usando o pré-processador LESS CSS, você poderia escrever o exemplo anterior assim:

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

Vários pré-processadores CSS populares estão disponíveis hoje, todos com conjuntos de recursos variados. Entre os mais populares estão MENOS,Sass e Estilete

Por outro lado, este exemplo exige que seu widget use contêineres de nível superior com IDs, o que não será prático para widgets que podem ser renderizados várias vezes na mesma página. Além disso, ele ainda não é à prova de balas: um editor pode seguir sua liderança e especificar em excesso suas próprias regras de CSS, resultando no mesmo problema que você tinha antes.

Mas esse é um cenário improvável, especialmente porque você especificou de forma redundante dois IDs em cada uma das regras. Você poderia, alternativamente, usar um, mas isso, é claro, seria mais vulnerável. A realidade é que a maioria dos editores usa regras sãs de CSS, e a especificação excessiva de suas regras como essa será compatível com a maioria delas.

Superespecificação de CSS não se mistura com ferramentas de qualidade de código

Se você pensar em superespecificar seu CSS dessa forma, talvez encontre um inimigo improvável: ferramentas que avaliam a qualidade de seu código CSS, como CSS Lint, Google Page Speed ​​e YSlow do Yahoo. Essas ferramentas indicarão que você está fazendo seletores CSS redundantes e aconselharão a remover esses seletores para reduzir o tamanho do arquivo e melhorar o desempenho do CSS dos navegadores. Infelizmente, essas ferramentas não são programadas com scripts de terceiros em mente e não avaliam a utilidade da superespecificação de CSS. Os benefícios da especificação excessiva para aplicativos de terceiros superam o tamanho de arquivo extra e o impacto de desempenho minúsculo.

Abusando! Importante

Se você acha que superespecificar seu CSS com IDs extras ou seletores de classe não vai longe o suficiente, você pode quebrar a opção nuclear: a palavra-chave! Importante. As propriedades dentro de uma regra de CSS que ostentam a palavra-chave! Importante são as prioridades mais altas de todos, mesmo acima dos estilos inline. Isso ocorre porque a importante palavra-chave foi projetada para fornecer aos usuários do navegador uma maneira infalível de substituir estilos de "autor" (editor), no caso de plug-ins do navegador ou estilos específicos do site. Você pode abusar! Importante usando-o em todas as suas propriedades CSS, efetivamente priorizando-as sobre todas as outras regras.

Veja como você pode usar a importante palavra-chave em uma única regra de CSS:

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

Como é por propriedade, a palavra-chave importante precisa ser repetida dessa forma, o que pode se tornar um empecilho em uma folha de estilo longa e complexa. Mas, em troca, você obtém um conjunto sólido de folhas de estilo que provavelmente não serão redefinidas pela página do editor.

Ainda é concebível que a editora possa, por sua vez, usar os elementos importantes e definir seus próprios estilos, e nesse momento eles estão propositadamente direcionando seus elementos para personalização. Por um lado, isso pode ser frustrante se você estiver tentando manter uma aparência consistente. Mas, se você decidiu permitir que os editores personalizem seu widget, esse é provavelmente o comportamento desejado.

Uma coisa deve ficar clara: compartilhar o DOM com o editor pode tornar particularmente difícil processar um widget de estilo consistente. Embora você possa adotar medidas para especificar suas regras de CSS para reduzir a probabilidade de conflitos, é sempre possível que o editor segmente seus elementos com suas regras, acidental ou propositalmente.

Mas se compartilhar o DOM com o editor é o que está causando tanta dor, é possível renderizar seu widget fora do DOM? Por que sim - sim você pode.

Resumo

Para um aplicativo JavaScript de terceiros, a injeção de HTML e CSS na página do editor exige mais cuidado do que se você estivesse adicionando marcação a um ambiente “seguro”. Você deve certificar-se de que, ao enviar HTML para a página, não esteja reduzindo a velocidade da página com uma operação de bloqueio. Você também deve considerar que seu script pode ser incluído várias vezes na mesma página e deve processar várias instâncias normalmente. Além disso, você deve escolher um método ideal para injetar CSS na página do editor, seja inlining todos os seus estilos, acrescentando elementos de link ou incorporando regras CSS em seu JavaScript.

Mas apenas obter HTML e CSS na página não é suficiente. Você tem que reconhecer que os elementos introduzidos no DOM podem entrar em conflito com a página principal. Você também deve considerar como seus estilos podem entrar em conflito com os estilos existentes definidos pelo editor. Você pode usar várias técnicas para reduzir o impacto de estilos pai em seu widget: especifique em excesso suas regras de CSS ou apresente seu conteúdo por trás de um iframe, seja um iframe sem src ou um que contenha um documento HTML externo.

Quais técnicas você usa ao produzir CSS e HTML para terceiros? Você já voltou a ser importante? Deixe-nos saber nos comentários.

Imagem em destaque / miniatura, imagem de defesa via Shutterstock.