2011-02-11 12 views
5

Estoy escribiendo una extensión de Google Chrome que ejecuta un script de contenido en cada página. En mi script de contenido, inyecto un <div> con algunos <ul> y <li> hijos en la página. Especifico algunos estilos para estos elementos en una hoja de estilo.cómo no heredar estilos en un script de contenido de extensión de Chrome

Pero he encontrado que en algunas páginas aleatorias mis elementos heredarán estilos de los definidos en la página web ya que no he especificado todas las propiedades de estilo para mis divs.

¿Cuál es la mejor forma en que puedo evitar que los elementos inyectados hereden estos estilos?

Me parece que pude ya sea:

  • especificar cada estilo individual en mi hoja de estilo, o
  • que podría poner (por ejemplo, viendo lo que los estilos calculados son cuando no hay interferencia). mi <div> dentro de . Sin embargo, tendré que hacer un mensaje hella pasando entre el iframe de mi script de contenido y la página de origen, ya que la url chrome:// de mi iframe src y las urls http:// de las páginas fuente se considerarán de origen cruzado.
+1

Técnicamente, hay una tercera ruta: [Shadow DOM] (http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/). Pero no conozco un ejemplo completo de trabajo para una extensión de Chrome. Hay una extensión [display-anchors] (https://github.com/Rob--W/display-anchors) que lo usa, pero no es una GUI que se comunica con la extensión. – Xan

+0

Cómo se carga el orden de los archivos css en la página. ¿Es como la primera página que se carga css y luego los archivos css de script de contenido? ¿o viceversa? –

+0

las respuestas están desactualizadas ahora, puede usar 'all: initial;' en css now –

Respuesta

1

Me gustaría ir con la primera opción - para especificar completamente el estilo de los elementos que utiliza. Pero esto es un poco más complicado de lo que pensaba.

Primero, debe especificar completamente el elemento del contenedor. Luego, para sus descendientes, debe decir que también deben usar los valores predeterminados o heredar de sus padres (hasta el contenedor). Finalmente, debe especificar el aspecto de todos los demás elementos para que no sean todos los tramos simples.

Las API relevantes son getComputedStyle y la interfaz CSSStyleSheet de DOM Level 2 Style. Puede usar todos los valores excepto width y height, que deben ser auto de forma predeterminada. También debe descargar una hoja de estilo predeterminada, como Webkit user agent stylesheet. Luego puede llamar a la siguiente función para crear una hoja de estilo completa que pueda insertar en el documento.

Tenga en cuenta que cuando inserte la hoja de estilo en el documento de destino, tendrá que hacer que el selector de contenedor sea lo más específico posible porque la página web podría dar reglas que tengan un specificity superior a sus reglas. Por ejemplo, en <html id=a><head id=b><style>#a #b * {weird overrides}</style></head>, #a #b * tiene una especificidad mayor que #yourId div. Pero me imagino que esto no es común.

Nota: por alguna razón, Chrome me está dando el error "Error al cargar el recurso" cuando cargo el CSS, a menos que ya esté en un <link> del documento actual. Entonces debería incluir html.css en la página que llama a esta función también.

// CSS 2.1 inherited prpoerties 
var inheritedProperties = [ 
    'azimuth', 'border-collapse', 'border-spacing', 'caption-side', 
    'color', 'cursor', 'direction', 'elevation', 'empty-cells', 
    'font-family', 'font-size', 'font-style', 'font-variant', 
    'font-weight', 'font', 'letter-spacing', 'line-height', 
    'list-style-image', 'list-style-position', 'list-style-type', 
    'list-style', 'orphans', 'pitch-range', 'pitch', 'quotes', 
    'richness', 'speak-header', 'speak-numeral', 'speak-punctuation', 
    'speak', 'speech-rate', 'stress', 'text-align', 'text-indent', 
    'text-transform', 'visibility', 'voice-family', 'volume', 
    'white-space', 'widows', 'word-spacing']; 
// CSS Text Level 3 properties that inherit http://www.w3.org/TR/css3-text/ 
inheritedProperties.push(
    'hanging-punctuation', 'line-break', 'punctuation-trim', 
    'text-align-last', 'text-autospace', 'text-decoration-skip', 
    'text-emphasis', 'text-emphasis-color', 'text-emphasis-position', 
    'text-emphasis-style', 'text-justify', 'text-outline', 
    'text-shadow', 'text-underline-position', 'text-wrap', 
    'white-space-collapsing', 'word-break', 'word-wrap'); 
/** 
* Example usage: 
     var fullStylesheet = completeStylesheet('#container', 'html.css').map(
      function(ruleInfo) { 
       return ruleInfo.selectorText + ' {' + ruleInfo.cssText + '}'; 
      }).join('\n'); 
* @param {string} containerSelector The most specific selector you can think 
*  of for the container element; e.g. #container. It had better be more 
*  specific than any other selector that might affect the elements inside. 
* @param {string=} defaultStylesheetLocation If specified, the location of the 
*  default stylesheet. Note that this script must be able to access that 
*  locatoin under same-origin policy. 
* @return {Array.<{selectorText: string, cssText: string}>} rules 
*/ 
var completeStylesheet = function(containerSelector, 
            defaultStylesheetLocation) { 
    var rules = []; 
    var iframe = document.createElement('iframe'); 
    iframe.style.display = 'none'; 
    document.body.appendChild(iframe); // initializes contentDocument 
    try { 
    var span = iframe.contentDocument.createElement('span'); 
    iframe.contentDocument.body.appendChild(span); 
    /** @type {CSSStyleDeclaration} */ 
    var basicStyle = iframe.contentDocument.defaultView.getComputedStyle(span); 
    var allPropertyValues = {}; 
    Array.prototype.forEach.call(basicStyle, function(property) { 
     allPropertyValues[property] = basicStyle[property]; 
    }); 
    // Properties whose used value differs from computed value, and that 
    // don't have a default value of 0, should stay at 'auto'. 
    allPropertyValues['width'] = allPropertyValues['height'] = 'auto'; 
    var declarations = []; 
    for (var property in allPropertyValues) { 
     var declaration = property + ': ' + allPropertyValues[property] + ';'; 
     declarations.push(declaration); 
    } 
    // Initial values of all properties for the container element and 
    // its descendants 
    rules.push({selectorText: containerSelector + ', ' + 
           containerSelector + ' *', 
       cssText: declarations.join(' ')}); 

    // For descendants, some of the properties should inherit instead 
    // (mostly dealing with text). 
    rules.push({selectorText: containerSelector + ' *', 
       cssText: inheritedProperties.map(
        function(property) { 
         return property + ': inherit;' 
        }).join(' ')}); 

    if (defaultStylesheetLocation) { 
     var link = iframe.contentDocument.createElement('link'); 
     link.rel = 'stylesheet'; 
     link.href = defaultStylesheetLocation; 
     iframe.contentDocument.head.appendChild(link); 
     /** @type {CSSStyleSheet} */ 
     var sheet = link.sheet; 
     Array.prototype.forEach.call(
      sheet.cssRules, 
      /** @param {CSSStyleRule} cssRule */ 
      function(cssRule) { 
     rules.push({ 
      selectorText: containerSelector + ' ' + cssRule.selectorText, 
      cssText: cssRule.style.cssText}); 
     }); 
    } 
    return rules; 
    } finally { 
    document.body.removeChild(iframe); 
    } 
}; 
+0

Genial, gracias por la respuesta detallada @yonran. Re: el error de CSS Chrome, incluyo mi referencia de hoja de estilo en la extensión manifest.json: '" content_scripts ": [{" matches ": [" http: // */* "]," css ": [" my. css "]}]' y cada vez que necesito hacer referencia a un recurso local en mi script de contenido lo obtengo a través de 'chrome.extension.getURL (" ... ");' – mark

+0

Tengo un problema con el anterior. Cuando intento 'iframe.contentDocument.defaultView.getComputedStyle (span)', el problema es que 'iframe.contentDocument.defaultView' no está definido. – mark

+0

Ah, los problemas que tenía estaban relacionados con un error de Chrome http://code.google.com/p/chromium/issues/detail?id=49001. El problema se manifestó cuando estaba usando el protocolo file: //. Configuré un servidor web local y luego pude acceder a la propiedad cssRules deseada utilizando el protocolo http: //. – mark

0

Recientemente he creado Boundary, una biblioteca CSS + JS para resolver problemas como este. Boundary crea elementos que están completamente separados del CSS de la página web existente.

Tome la creación de un cuadro de diálogo, por ejemplo.Después de la instalación del límite, usted puede hacer esto en el script contenido

var dialog = Boundary.createBox("yourDialogID", "yourDialogClassName"); 

Boundary.loadBoxCSS("#yourDialogID", "style-for-elems-in-dialog.css"); 

Boundary.appendToBox(
    "#yourDialogID", 
    "<button id='submit_button'>submit</button>" 
); 

Boundary.find("#submit_button").click(function() { 
    // find() function returns a regular jQuery DOM element 
    // so you can do whatever you want with it. 
    // some js after button is clicked. 
}); 

Los elementos dentro de #yourDialogID no se verán afectados por la página web existente.

Espero que esto ayude. Por favor avísame si tienes alguna pregunta.

https://github.com/liviavinci/Boundary

+0

Por favor ** pare y lea mis comentarios ** en [su respuesta anterior] (http://stackoverflow.com/a/26431160/934239). Si continúas copiando y pegando esta respuesta sin ninguna mejora, tendré que marcarla, a pesar de su utilidad. – Xan

Cuestiones relacionadas