Подтвердить что ты не робот

Как действительно изолировать таблицы стилей в расширении Google Chrome?

Я написал расширение google chrome, которое открывает диалоговое окно с полем автозаполнения и собственным стилем, но есть некоторые сайты, где мой CSS полностью разбит, что выглядит не очень красивым.

Я знаю об изоляции стилей с помощью iFrames, но в расширении Google Chrome нет возможности изолировать мои HTML и CSS таким образом. Другим методом является перенос всех моих вещей в разделенный div с его собственным идентификатором и относительными стилями для этого идентификатора, и я делаю это, но, похоже, он не работает на некоторых сайтах с перегрузкой жестких тегов или "важными" директивами в код CSS.

Итак, я хочу знать, есть ли способ действительно изолировать мои стили удобным способом или это моя плохая карма, чтобы перегрузить каждое небольшое свойство CSS, чтобы исправить ту или иную ошибку стиля на каждом сайте?

Кстати, я установил свой манифест, чтобы загрузить все вещи в "document_end", но я вижу, что он не применяется к таблицам стилей, которые загружаются каждый раз перед тем, как DOM готов.
4b9b3361

Ответ 1

Во время запроса вопроса единственным вариантом было либо использовать iframes, либо таблицы стилей с очень высоким specificity и явно задайте все свойства, которые могут повлиять на стили. Последний метод очень громоздкий, потому что всегда будет какое-то свойство, которое вас упускает. Следовательно, единственным используемым методом для выделения таблиц стилей было использование iframes.

Решение этой проблемы - удаление стилей без iframes - Shadow DOM (начиная с Chrome 25). Вы можете найти учебник по HTML5 Rocks. Для реального расширения Chrome, использующего Shadow DOM для изоляции стилей, см. Display #Anchors (исходный код здесь).

Ответ 2

Поскольку я недавно прошел перчатку этой проблемы, я хочу поделиться некоторой информацией, которая мне кажется ценной.

Во-первых, ответ Роб W верен. Тень DOM - правильное решение этой проблемы. Однако в моем случае мне не только нужна изоляция CSS, но также нужны события JavaScript. Например, что произойдет, если пользователь нажмет кнопку, которая живет в изолированном HTML? Это становится действительно уродливым только с Shadow DOM, но у нас есть другая технология веб-компонентов, Custom Elements, для спасения. За исключением того, что на момент написания этой статьи есть ошибка в chrome, которая предотвращает создание пользовательского элемента в chrome-расширениях. См. Мои вопросы здесь и здесь и ошибка здесь.

Итак, где это нас покидает? Я считаю, что лучшим решением сегодня является IFrames, с которым я и пошел. Статья shahalpk связана велика, но она описывает только часть процесса. Вот как я это сделал:

Сначала создайте файл html и js файл для вашего изолированного виджета. Все внутри этих файлов будет работать в изолированной среде в iframe. Не забудьте загрузить файл js из html файла.

//iframe.js
var button = document.querySelector('.my-button');
button.addEventListener('click', function() {
    // do useful things
});

//iframe.html
<style>
/* css */
</style>
<button class='my-button'>Hi there</button>
<script src='iframe.js'></script> 

Далее, внутри вашего содержимого script создайте элемент iframe в javascript. Вам нужно сделать это в javascript, потому что вам нужно использовать chrome.extension.getURL, чтобы захватить ваш файл iframe html:

var iframe = document.createElement('iframe');
iframe.src = chrome.extension.getURL("iframe.html");
document.body.appendChild(iframe);

И что это.

Одна вещь, о которой нужно помнить: если вам нужно обмениваться между iframe и остальным содержимым script, вам нужно сделать chrome.runtime.sendMessage() на фоновом изображении, а затем chrome.tabs.sendMessage от фоновой страницы до вкладки. Они не могут напрямую общаться.

EDIT: я написал сообщение в блоге, в котором подробно описано все, что я узнал в ходе своего процесса, включая полный пример расширения chrome и множество ссылок на различную информацию:

http://anderspitman.com/2014/08/04/chrome-extension-content-script-stylesheet-isolation/

EDIT2: я не запускаю свой блог: здесь источник для сообщения в блоге и репо кода для примеров:

Сообщение в блоге

Пример источника

Ответ 3

Используйте либо all

.some-selector {
    all: initial;
}

.some-selector * {
    all: unset;
}

или используйте Shadow DOM

Библиотека

function Widget(nodeName, appendTo){
  this.outer = document.createElement(nodeName || 'DIV');
  this.outer.className = 'extension-widget-' + chrome.runtime.id;
  this.inner = this.outer.createShadowRoot();
  (appendTo || document.body).appendChild(this.outer);
}

Widget.prototype.show = function(){
  this.outer.style.display = 'block';
  return this;
};

Widget.prototype.hide = function(){
  this.outer.style.display = 'none';
  return this;
};

Использование

var myWidget = new Widget();
myWidget.inner.innerHTML = '<h1>myWidget</h1>';

Вы можете получить доступ к содержимому виджета с помощью myWidget.inner и внешнего через myWidget.outer.

Стили

/* 
 * Reset Widget Wrapper Element 
 */
[email protected]@extension_id__ {
  background: none;
  border: none;
  bottom: auto;
  box-shadow: none;
  color: black;
  cursor: auto;
  display: inline;
  float: none;
  font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif;
  font-size: inherit;
  font-style: normal;
  font-variant: normal;
  font-weight: normal;
  height: auto;
  left: auto;
  letter-spacing: 0;
  line-height: 100%;
  margin: 0;
  max-height: none;
  max-width: none;
  min-height: 0;
  min-width: 0;
  opacity: 1;
  padding: 0;
  position: static;
  right: auto;
  text-align: left;
  text-decoration: none;
  text-indent: 0;
  text-shadow: none;
  text-transform: none;
  top: auto;
  vertical-align: baseline;
  white-space: normal;
  width: auto;
  z-index: 2147483648;
}

/* 
 * Add your own styles here 
 * but always prefix them with:
 * 
 *   [email protected]@extension_id__ 
 *   
 */

[email protected]@extension_id__{
  position: fixed;
  top: 100px;
  margin: 0 auto;
  left: 0;
  right: 0;
  width: 500px;
}

[email protected]@extension_id__::shadow h1 {
  display: block;
  margin: 0 auto;
  padding: 20px;
  background-color: yellow;
  border: 10px solid green;
  font-size: 20px;
  text-align: center;
}

Ответ 4

Недавно я создал Boundary, библиотеку CSS + JS для решения таких проблем. Граница создает элементы, которые полностью отделены от существующей веб-страницы CSS.

Возьмем, например, создание диалогового окна. После установки Boundary вы можете сделать это в своем контенте script

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() {
  // some js after button is clicked.
});

Элементы в #yourDialogID не будут затронуты существующей веб-страницей. И функция find() возвращает регулярный элемент DOM jQuery, поэтому вы можете делать с ним все, что хотите.

Надеюсь, это поможет. Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы.

https://github.com/liviavinci/Boundary

Ответ 5

Используйте iframes. Это обходной путь, но отлично работает.

Maxime написал статью на нем.