Статьи

HTML5, старые браузеры и Shiv

HTML5 представил несколько семантических элементов, которые не поддерживаются в старых браузерах. Некоторые из этих новых элементов ничем не отличаются от общих блочных элементов, поэтому они не создают проблем совместимости. Все, что вам нужно для обеспечения совместимости, это добавить на ваш сайт правило CSS, которое заставляет соответствующие элементы вести себя как блочные элементы.

Но Internet Explorer версии 8 и ниже представляет собой проблему. Любой элемент, не входящий в официальный список элементов, не может быть стилизован с помощью CSS. Это означает, что мы не можем заставить себя вести себя как блочные элементы или дать им какое-либо форматирование.

Например, следующий код не будет работать.

<style> section {display: block} </style> <section>This is on its own line.</section> <section>This should appear on a separate line.</section> 

Но это не все. Эти новые элементы ведут себя так, как будто их не существует. Например, следующий CSS не будет работать, так как элемент section не будет соответствовать универсальному селектору.

 <style> body * span {color: red} </style> <body> <section> <span>This should be red, but won't be red in IE 8.</span> </section> </body> 

К счастью для нас, существует обходной путь, который позволяет Internet Explorer (IE) распознавать эти новые элементы, позволяя им стилизоваться, и, таким образом, дает нам полное использование этих новых семантических тегов. Это инструмент под названием HTML5Shiv .

Как отмечено на связанной странице Google, «shiv» и «shim» являются взаимозаменяемыми терминами в этом контексте.

Но как мы перешли от IE, даже не признающего существование этого элемента, к возможности использовать его?

Хитрость в том, что вызов document.createElement("section") внезапно заставит IE распознать элемент section . Никто не знает почему, но это работает, и вам даже не нужно использовать узел, возвращаемый этой функцией.

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

Вам нужно будет вызывать его для каждого нового HTML5-элемента следующим образом:

 "abbr article aside audio bdi canvas data datalist details figcaption figure "+ "footer header hgroup main mark meter nav output progress section " + "summary template time video" .replace(/w+/g, function(a){ document.createElement(a) }); 

Обратите внимание, что мы используем метод replace объекта string для краткой итерации по каждой смежной длине символов, соответствующих регулярному выражению, и выполняем функцию обратного вызова для каждого блока символов, который в свою очередь вызывает createElement .

Далее мы будем называть этот метод «shivving the document», чтобы документ мог отображать новые элементы HTML5.

Теперь наши предыдущие два примера HTML работают. Но это еще не все.

Подводный камень 1: HTML5 и innerHTML

Если HTML генерируется с использованием innerHTML и он вызывается на узле, который в данный момент не присоединен к документу (AKA — осиротевший узел), то это снова и снова дежа вю. Следующие два примера не будут отображать элемент section , даже если он выполняется на документе, который уже удален.

 var n1 = document.getElementById("n1"); n1.parentNode.removeChild(n1); n1.innerHTML = "<section>Sect 1</section>"; //won't work 
 var n2 = document.createElement("div"); n2.innerHTML = "<section>Sect 2</section>"; //won't work 

Во втором примере выше, если мы добавим узел к документу перед вызовом innerHTML , он будет работать:

 var n2 = document.createElement("div"); document.body.appendChild(n2); n2.innerHTML = "<section>Sect 2</section>"; //works 

Мы можем заключить, что, хотя мы и раньше переносили документ, потерянные элементы не получают преимущества от shiv при вызове innerHTML .

Что мы можем сделать? Для начала, всякий раз, когда нам нужно установить innerHTML мы должны сначала добавить его в документ. Альтернатива — сначала открыть свойство document для сироты, прежде чем работать с ним.

Сначала давайте поместим наш shiv в его собственную функцию.

 function iehtml5shiv(doc) { "abbr article aside audio bdi canvas data datalist details " + "figcaption figure footer header hgroup main mark meter nav " + "output progress section summary template time video" .replace(/w+/g, function(a){ doc.createElement(a) }); } 

В следующий раз, когда у нас будет элемент-сирота, мы можем сделать это:

 var n1 = document.createElement("div"); iehtml5shiv(n1.document); n1.innerHTML = "<section>Sect 1</section>"; //works 

Обратите внимание, что это похоже на перемещение документа, но на свойстве document элемента. И обратите внимание, что мы получаем доступ к document вместо ownerDocument . Обе вещи разные, как показано здесь:

 alert(n1.document == document); //false alert(n1.ownerDocument == document); //true 

Теперь у нас есть два метода, чтобы убедиться, что наш вызов innerHTML работает при обработке элементов HTML5.

Подводный камень 2: cloneNode

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

Обратите внимание, что в приведенном ниже элементе есть двоеточия в его nodeName , что означает, что он запутан для элемента из другого пространства имен.

 var n2 = n1.cloneNode(true); alert(n2.innerHTML); //outputs: <:section>Sect 1</:section> 

Это происходит, даже если узел уже был прикреплен к документу.

Здесь мы мало что можем сделать, кроме как развернуть собственную реализацию cloneNode , что достаточно тривиально.

Ловушка 3: Печать

Всякий раз, когда вы печатаете веб-страницу, IE, кажется, создает новый документ перед печатью, что означает, что все обходные пути Shiv не сохраняются.

Вы не можете многое сделать, чтобы смягчить это. Инструмент HTML5Shiv работает вокруг этого, прослушивая событие onbeforeprint и заменяя все элементы HTML5 на странице обычными элементами, а затем делает обратное onafterprint события onafterprint .

К счастью, инструмент HTML5Shiv делает это хорошо для нас.

Ссылки