HTML5 <meter> таг
В урока си Разлики в HTML4 и HTML5 споменавам <meter>
тага, казвайки, че той няма вградена визуална презентация в браузърите. След бърза справка се оказа, че греша и повечето браузъри вече представят този таг като правоъгълник запълнен до определено ниво. В този урок ще дам няколко насоки как да използваме най-правилно този таг и как да се уверим, че той ще изглежда правилно и на по-стари браузъри.
Начален set-up
Нека започнем със структурата на една съвсем елементарна страница, съдържаща <meter>
таг:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>meter tag</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script type="text/javascript" src="jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="func.js"></script>
</head>
<body>
<h1>Колко е 3/10:</h1>
<meter id="progress" min="0" max="100" value="30" title="percents">30%</meter>
</body>
</html>
Стандартни HTML5 Doctype, UTF-8 charset, заглавие, stely.css файл, който ще добавим след малко, включване на jQuery 1.8.3 и func.js файл, който също ще добавим в последствие.
В <body>
-то имаме заглавие и <meter>
. На <meter>
-а сме задали id
, min
, max
, value
и title
атрибути. min
и max
може би се досещате, че показват съответно минималната и максималната стойност на нашия <meter>
. Най-често минималната стойност би била 0, но при по-особени обстоятелства може да е различна. Например минималната оценка в училище е 2. Важното е обаче тези минимум и максимум да са числа.
value
пък изразява текущата стойност и до там ще бъде запълнен нашият <meter>
.
title
упоменава мерната единица.
Нека сега добавим някакви основни стилове към страницата:
@charset "utf-8";
* { margin: 0; padding: 0; }
html, body { width: 100%; height: 100%; }
body { background: #E0E0E0; color: #000; font: normal 12px Arial, Helvetica, sans-serif; }
h1 { padding-top: 30px; }
h1, #progress { font-size: 250%; text-align: center; }
#progress { display: block; width: 400px; height: 30px; margin: 20px auto 30px; border: 1px solid #B0B0B0; }
Начален резултат
Ето какво имаме за сега при най-популярните браузъри:
Както виждате Chrome, Firefox и Opera имат поддръжка за визуализация на тага. Дори и зеленият цвят на запълване е почти еднакъв (само на Opera е по-светъл). Разликите са, че Chrome и Firefox добавят и светлосенки.
Проблемът е, че при Internet Explorer (дори версия 10) и Safari нещата не изглеждат толкова приятно. За да накараме нашия meter
да изглежда сносно и там трябва да използваме малко JavaScript, с който да направим няколко
DOM манипулации
Идеята тук е следната: да направим един <div>
контейнер за цялостния <meter>
, като вътре в него се съдържа друг <div>
, който да отговаря за запълването.
Трябва обаче да добавим и следните редове към нашите стилове:
#progress { position: relative; }
#progress .value { width: 0; height: 100%; margin: 0 auto 0 0; background: #90BE29; }
Задаваме margin: 0 auto 0 0;
, защото на IE7 div.value
се центрира в parent container-а си с равни по стойност margin-и от ляво и дясно.
Забележка: макар и в този случай да използваме DIV
тагове, въпросните промени могат да се направят и с други (например <span>
), в случай, че вашият <meter>
е поставен в inline
елемент.
Ето го и JavaScript-а който ще добавим, а по-долу следват и обяснения:
var newTags = ['meter'];
for (var t in newTags) {
document.createElement(newTags[t]);
}
jQuery(function ($) {
// !document.createElement('meter').hasOwnProperty('min') -- not working in Firefox
if (document.createElement('meter')['min'] == undefined) {
$('meter').each(function () {
var divMeter = $('<div id="' + $(this).attr('id') + '"><div class="value"></div></div>');
var value = ( $(this).attr('value') - $(this).attr('min') ) / ( $(this).attr('max') - $(this).attr('min') );
divMeter.find('.value').css('width', value * 100 + '%');
$(this).replaceWith(divMeter);
});
}
});
В масива newTags
записваме списък от всички HTML5 тагове, които използваме, за да добавим поддръжка за тях в IE7/8. По принцип може би бихте желали да си имате порция код, която да добавя всички HTML5 тагове, но за да опростя примера съм добавил само meter
.
Продължаваме с функция, която се изпълнява на DOMContentLoaded. В тази функция първо правим проверка дали текущият браузър поддържа <meter>
тага. Подобна проверка можем да направим за всеки един таг, като създадем нова инстанция програматично от JavaScript по следния начин:
var meter = document.createElement('meter');
Вместо „meter“ може да се използва името на всеки друг таг.
След като сме създали нова инстанция можем да направим проверка дали този нов обект поддържа property-та характерни за него. Тъй като <meter>
тагът поддържа атрибут min
можем да направим проверка дали като DOM елемент той има property min
по следния начин:
var meter = document.createElement('meter');
var lacksSupport = !meter.hasOwnProperty('min');
Тествайки този метод обаче срещнах проблеми с Firefox, затова съм закоментирал тази проверка и съм опитал по друг начин:
var lacksSupport = document.createElement('meter')['min'] == undefined;
Тук отново създаваме нова инстанция, но директно взимаме нейното property min
и го сравняваме с недефинираната променлива undefined
.
undefined
Този момент с недефинираната променлива е малко тънък, но може да го срещнете на много места, затова ето няколко думи по въпроса:
Още в един от началните уроци за JavaScript говорихме, че променливите си имат тип. Този тип може да се достъпи с typeof(varName)
. Ако опитаме да вземем типа на променлива, която не е дефинирана, резултатът от функцията typeof()
ще бъде 'undefined'
. Нарочно изписвам резултата в кавички, като по този начин наблягам, че резултатът сам по себе си е string, но стойността му е „undefined“.
В JavaScript няма запазена дума undefined
, така че можем да създадем такава променлива. От друга страна, ако не сме я създали, а се опитаме да достъпим типа и чрез typeof()
, то бихме получили резултат 'undefined'
.
В примера по-горе можем да използваме:
var lacksSupport = typeof(document.createElement('meter')['min']) == 'undefined';
но сме избрали по-кратък вариант, в който да пропуснем typeof
и да проверим дали това property (min) липсва така както липсва дефиниция за променливата undefined
.
Този кратък вариант няма да работи обаче, ако някой реши да си прави гавра и вземе, че създаде променлива undefined
. Имайте едно на ум, че ако някой се постарае може да счупи този кратък вариант.
Задвижване на meter на IE
Да се върнем сега на <meter>
-а.
След като сме направили проверка дали браузърът не поддържа функционалността на този таг изпълняваме едно кратко заместване на всички места, където тагът се среща в markup-а.
Създаваме нашия контейнер с вложен <div>
, който да изразява стойност, като му задаваме ID, което да е същото като на <meter>
-а, който заменяме:
var divMeter = $('<div id="' + $(this).attr('id') + '"><div class="value"></div></div>');
След това изчисляваме стойността на <meter>
-а в проценти и използваме тези проценти, за да променим широчината на запълващия div.value
.
var value = ( $(this).attr('value') - $(this).attr('min') ) / ( $(this).attr('max') - $(this).attr('min') );
divMeter.find('.value').css('width', value * 100 + '%');
Накрая просто заместваме markup-а на <meter>
-а с този, който сме подготвили в променливата divMeter
:
$(this).replaceWith(divMeter);
Можете да видите крайния вариант на https://magadanski.com/demo/meter/
Ако искате <meter>
-а да се вижда еднакво на всички браузъри можете да премахнете проверката за поддръжка на тага и JavaScript-ът да се изпълни за всички браузъри, в следствие на което роля ще оказват само стиловете, които сте добавили за допълнителните тагове.