Я уже
касался этой темы и давал
ссылку на решение. Оно, однако же, не вполне хорошо. Во-первых, оно не валидно, во-вторых, рассчитано на какие-то допотопные браузеры, коими уже никто не пользуется, но, в-третьих, не работает с современными браузерами (строго говоря, оно вообще не работает в том виде, в каком дано).
Однако, основная идея решения верна, поэтому попытаемся сделать его работоспособным и современным. Отчасти я сделал это тогда же, осенью, а сейчас попытаюсь дойти до конца и изложить сделанное.
Для начала, есть проблема вот с этой строчкой:
Функция в ней не выполняется, если только мы не перенесём её вызов на новую строчку. Только в XHTML экранирование будет выполняться ещё сложнее, посему вынесем-ка мы вызов функции во внешний скрипт:
Идём дальше. Нынешний код считает, что Firefox, Chrome и Safari для отображения SVG нуждаются в плагине, а Opera в этом отношении вообще безнадёжна. Однако, Opera имеет нативную поддержку SVG с версии 8.0 (19 апреля 2005 г.), Firefox - с версии 1.5 (30 ноября 2005 г.), Safari - с версии 3.0 (11 июня 2007 г.), а Chrome - с рождения (2 сентября 2008 г.). Фактически, все ухищрения нужны только для «Просмотрщика Интернета», сиречь Internet Explorer, у коего такая поддержка ожидается лишь в 9-й версии.
Тогда все три подключенных скрипта можно скрыть от прочих браузеров в условный комментарий (ну и насчёт языка перестаём притворяться, что это - JavaScript):
Там, где непосредственно подключается SVG-картинка мы можем заключить рекомендованный код в такой же комментарий, а следом написать что-нибудь такое:
В сумме получается довольно громоздкая конструкция, да ещё смешивающая представление с поведением. На самом деле можно просто написать:
А в подключаемом скрипте viewSVJ.js, если SVG-плагин всё-таки не установлен, будем перебирать элементы embed и заменять их на предупреждения со ссылками:
checkAndGetSVGViewer();
window.attachEvent(
"onload",
function(){
if(window.svgInstalled)//если SVG-плагин установлен
return;
var embeds=document.getElementsByTagName("embed");
for(var embedNumber=0, embedTypeAttr; embedNumberClick here for more information.
";
}
}
);
Но HTML-код всё равно выглядит чрезмерно раздутым. Ведь условный комментарий с элементом embed надо писать для каждой SVG-картинки, а ссылки на несколько скриптов (и тоже с условным комментарием) - для каждой содержащей их страницы! Конечно, существует шаблонизация, но… Вдобавок, эти скрипты замусоривают глобальное пространство имён, а лезть разбираться в их устаревший код не хочется.
Укротим сперва скрипты. Будем цеплять к странице один скрипт fixSVG.js, куда пихнём весь
фикс для Webkit-браузеров, а для IE напишем свою ветку, в которой будем подгружать в динамически созданный плавающий фрейм скрипты от «Эдоуби» (Adobe), выполнять с их помощью проверку на наличие установленного SVG-плагина, если он не установлен, подменять картинки на соответствующие уведомления со ссылкой, и, наконец, удалять этот фрейм. Детали реализации смотрим ниже в окончательном решении.
Наконец, от тяжеловесной конструкции на месте каждой картинки можно избавиться, если пожертвовать браузерами IE с установленным SVG-плагином, но отключенным JScript. Я склонен решительно пожертвовать. Всем известно, насколько этот браузер требует костылей для соблюдения стандартов, так что если человек отключает в нём скрипты, он молчаливо соглашается видеть Интернет «условно».
Можно писать просто:
Впрочем, если кому-то вышеописанный вариант дорог, как память, можно и так:
Затем для IE мы должны подменять элемент object на элемент embed, если SVG-плагин установлен, и на уведомление со ссылкой, если он ещё не установлен.
В заголовочной части страницы, как уже указано, пишем:
Файл fixSVG.js выглядит так (с использованием уже скриптового условного комментария):
/*@cc_on
if(@_jscript_version<9)
window.attachEvent(
"onload",
function(){
var iframe=document.createElement("iframe");
iframe.src="js/fixSVG_IE_5-8.html";
document.body.appendChild(iframe);
}
);
@*/
if(/AppleWebKit/.test(navigator.userAgent))
window.addEventListener(
"load",
function(){
var objects=document.getElementsByTagName("object");
for(var objectNumber=objects.length, objectNode, codebase, imageNode, attrNumber, attrNode; objectNumber--;){
objectNode=objects[objectNumber];
if(objectNode.getAttribute("type")==="image/svg+xml"){
imageNode=document.createElement("img");
codebase=objectNode.getAttribute("codebase");
imageNode.setAttribute("src", ((null===codebase)?"":codebase)+objectNode.getAttribute("data"));
imageNode.setAttribute("alt", "SVG");//совсем без alt нельзя по стандарту HTML
for(attrNumber=objectNode.attributes.length; attrNumber--;){
attrNode=objectNode.attributes[attrNumber];
if(-1===["declare", "classid", "codebase", "data", "type", "codetype", "archive", "standby", "tabindex"].indexOf(attrNode.name))
imageNode.setAttribute(attrNode.name, attrNode.value);
}
objectNode.parentNode.replaceChild(imageNode, objectNode);
}
}
},
false
);
Содержимое fixSVG_IE_5-8.html, подгружающееся в динамически созданный плавающий фрейм:
Fix SVG for IE 5-8
Скрипты svgcheck.js и svgcheck.vbs - адоубивские, нетронутые. А fixSVG_IE_5-8.js - наш:
checkAndGetSVGViewer();//проверяем наличие SVG-плагина
if(window.svgInstalled){
var objects=window.parent.document.getElementsByTagName("object");
for(var objectNumber=objects.length, objectNode, objectTypeAttr, embedNode, codebase, attrNumber, attrNode; objectNumber--;){
objectNode=objects[objectNumber];
objectTypeAttr=objectNode.attributes["type"];
if(objectTypeAttr=="image/svg+xml" || objectTypeAttr.value=="image/svg+xml"){
embedNode=window.parent.document.createElement("embed");
embedNode.setAttribute("type", "image/svg-xml");
embedNode.setAttribute("pluginspage", "
http://www.adobe.com/svg/viewer/install/");
embedNode.setAttribute("wmode", "transparent");//обеспечиваем прозрачность фона
codebase=objectNode.getAttribute("codebase");
embedNode.setAttribute("src", ((null===codebase)?"":codebase)+objectNode.getAttribute("data"));
for(attrNumber=objectNode.attributes.length; attrNumber--;){
attrNode=objectNode.attributes[attrNumber];
if(//сюрприз! IE не поддерживает indexOf!
attrNode.name!="archive" &&
attrNode.name!="classid" &&
attrNode.name!="codebase" &&
attrNode.name!="codetype" &&
attrNode.name!="data" &&
attrNode.name!="declare" &&
attrNode.name!="standby" &&
attrNode.name!="tabindex" &&
attrNode.name!="type" &&
attrNode.name!="usemap"
)
embedNode.setAttribute(attrNode.name, attrNode.value);
}
objectNode.parentNode.replaceChild(embedNode, objectNode);
}
}
}
else
if(window.svgViewerAvailable){//для проформы (мы знаем, что для IE 5-8 такой плагин есть!)
var message;
switch(navigator.browserLanguage.substr(0,2)){
case "ru":
message="Для просмотра этой страницы нужен";
break;
case "en":
default:
message="To view this page you need an";
}
var objects=window.parent.document.getElementsByTagName("object");
for(var objectNumber=objects.length, objectTypeAttr; objectNumber--;){
objectTypeAttr=objects[objectNumber].attributes["type"];//objects[objectNumber].getAttribute("type")===null!
if(objectTypeAttr=="image/svg+xml" || objectTypeAttr.value=="image/svg+xml")//тут учтён IE5
objects[objectNumber].outerHTML="
"+message+"
SVG viewer.
";
}
}
window.frameElement.parentNode.removeChild(window.frameElement);//удаляем плавающий фрейм, вызвавший этот скрипт
Вот так. Только помним при стилизации и скриптовании, что в Firefox, Opera и, очевидно, IE 9 будет элемент object, в Safari и Google Chrome (надеюсь, когда-нибудь везде) - img, а в IE 5-8 - embed.
Реализация этого решения развёрнута, для примера, на сайте
РГФ. На самом деле, там оно лишено большого практического смысла. Исходные картинки и в GIF-формате были просты и невелики, а стали бы ещё меньше при конвертации в PNG. Выигрыш в размере тут можно было бы получить разве что при использовании сжатых gzip-ом SVGZ, но я до сих пор бодаюсь с провайдером по поводу нежелания сервера отдавать нужный для этого HTTP-заголовок. И вообще, с семантической точки зрения, тут просится не SVG, а внедрённые шрифты, чем я тоже хотел бы заняться в дальнейшем.