Установка часов в правилах таблицы стилей CSS
Отредактировано, чтобы разрешить установку часов CSS из Javascript любое количество раз - оригинальная версия инициализировала часы один раз.
Первый шаг в этой версии - присвоить HTMLStyleELement значение id, скажем, «clockCSS», для облегчения доступа к таблице стилей. Либо назначьте значение идентификатора элементу LINK с помощью "rel = stylesheet", если используете внешнюю таблицу стилей.
Затем замените правило по ключевому кадру «по часовой стрелке» на отдельные правила «secFrames», «minFrames» и «hourFrames» для секунд, минут и часов соответственно. Включите новые правила ключевых кадров в таблицу стилей. Все они могут по умолчанию поворачиваться от 0 до 360 градусов.
Изменения CSS должны выглядеть примерно так же, как
.hourHand {
height : 48%;
background : transparent ;
border-right : 3px solid transparent;
animation : hourFrames 43200s linear infinite;
z-index : 5 ;
}
.minHand {
height : 48%;
border-right : 2px solid transparent;
animation : minFrames 3600s linear infinite;
z-index : 4 ;
}
.secHand {
height : 48%;
animation : secFrames 60s linear infinite ;
z-index : 6 ;
}
@keyframes hourFrames {
0% { transform : rotateZ(0deg);}
100% { transform : rotateZ(360deg);}
}
@keyframes minFrames {
0% { transform : rotateZ(0deg);}
100% { transform : rotateZ(360deg);}
}
@keyframes secFrames {
0% { transform : rotateZ(0deg);}
100% { transform : rotateZ(360deg);}
}
Теперь значения преобразования в правилах ключевых кадров можно установить в JavaScript:
// helper function to find a style sheet from its id value
function findSheetById( id) { // LINK rel=stylesheet or STYLE element id.
for( var i = 0; i < document.styleSheets.length; ++i) {
var sheet = document.styleSheets[i];
if( sheet.ownerNode.id == id) {
return sheet;
}
}
}
// helper function to find a keyframes rule (rule type 7) by name
function findKeyFramesRule( ruleList, name) {
for( var i = 0; i < ruleList.length; ++i) {
var rule = ruleList[i];
if( rule.type == 7 && rule.name == name)
return rule;
}
}
// clock setting code based on the stylesheet.
const clockSheetId = "clockCSS";
function setClockTransform( keyframesName, startDeg) {
let clockSheet = findSheetById(clockSheetId);
let atRule = findKeyFramesRule( clockSheet.cssRules, keyframesName);
let stops = atRule.cssRules;
stops[0].style.transform = "rotateZ(" + startDeg + "deg)";
stops[1].style.transform = "rotateZ(" + (startDeg+360) + "deg)";
}
function setClock( hour, min, sec, msec) {
// convert parameters to degrees
msec = msec || 0;
sec += msec/1000;
min += sec / 60;
hour = hour + min/60;
sec = sec%60 * 6;
min = min%60 * 6;
hour = hour%12 * 30;
setClockTransform( 'secFrames', sec);
setClockTransform( 'minFrames', min);
setClockTransform( 'hourFrames', hour);
}
// and test:
var now = new Date();
setClock( now.getHours(), now.getMinutes(), now.getSeconds())
Обратите внимание, что это упрощенно, поскольку оно опирается на известную структуру таблицы стилей. Это проверяется в последних версиях FireFox и Chrome. Однако в то время как IE11 устанавливал время и запускал его, другие проблемы CSS омрачали представление.
Тестовый код
"use strict";
// helper function to find a style sheet from its id value
function findSheetById( id) { // LINK rel=stylesheet or STYLE element id.
for( var i = 0; i < document.styleSheets.length; ++i) {
var sheet = document.styleSheets[i];
if( sheet.ownerNode.id == id) {
return sheet;
}
}
}
// helper function to find a keyframes rule (rule type 7) by name
function findKeyFramesRule( ruleList, name) {
for( var i = 0; i < ruleList.length; ++i) {
var rule = ruleList[i];
if( rule.type == 7 && rule.name == name)
return rule;
}
}
// clock setting code
const clockSheetId = "clockCSS";
function setClockTransform( keyframesName, startDeg) {
let clockSheet = findSheetById(clockSheetId);
let atRule = findKeyFramesRule( clockSheet.cssRules, keyframesName);
let stops = atRule.cssRules;
stops[0].style.transform = "rotateZ(" + startDeg + "deg)";
stops[1].style.transform = "rotateZ(" + (startDeg+360) + "deg)";
}
function setClock( hour, min, sec, msec) {
// convert parameters to degrees
msec = msec || 0;
sec += msec/1000;
min += sec / 60;
hour = hour + min/60;
sec = sec%60 * 6;
min = min%60 * 6;
hour = hour%12 * 30;
setClockTransform( 'secFrames', sec);
setClockTransform( 'minFrames', min);
setClockTransform( 'hourFrames', hour);
}
var now = new Date();
setClock( now.getHours(), now.getMinutes(), now.getSeconds())
<style type="text/css" id="clockCSS">
.frame {
position : absolute;
top : 0;
bottom : 0;
right : 0;
left : 0;
margin : auto;
width : 100%;
height : 100%;
border-radius : 50%;
border : 5px groove #000;
border-color : ;
/* transform : rotateZ(45deg); */
box-shadow : inset 0 0 10px 2px #000;
}
.secHand, .minHand, .hourHand {
background : ;
position : absolute ;
top : 2%;
bottom : ;
width : 0;
right : 0;
left : 0;
margin : auto;
transform-origin : 100% 100%;
/* transform : rotate(-45deg); */
border-right : 1px solid #000;
}
.hourCut, .miniCut {
position : absolute ;
width : 100% ;
bottom : 0;
}
.hourCut {
height : 50% ;
border-right : 3px solid #000;
}
.miniCut {
height : 70% ;
border-right : 2px solid #00f;
}
.hourHand {
height : 48%;
background : transparent ;
border-right : 3px solid transparent;
animation : hourFrames 43200s linear infinite;
z-index : 5 ;
}
.minHand {
height : 48%;
border-right : 2px solid transparent;
animation : minFrames 3600s linear infinite;
z-index : 4 ;
}
.secHand {
height : 48%;
animation : secFrames 60s linear infinite ;
z-index : 6 ;
}
@keyframes hourFrames {
0% { transform : rotateZ(0deg);}
100% { transform : rotateZ(360deg);}
}
@keyframes minFrames {
0% { transform : rotateZ(0deg);}
100% { transform : rotateZ(360deg);}
}
@keyframes secFrames {
0% { transform : rotateZ(0deg);}
100% { transform : rotateZ(360deg);}
}
.containerX {
position : absolute;
top : 0 ;
bottom : 0 ;
left : 0;
right : 0;
margin : auto;
height : 300px;
width : 300px;
}
.innerFrame, .smallFrame {
position : absolute ;
top : 0 ;
bottom : 0 ;
right : 0 ;
left : 0 ;
margin : auto ;
border : 1px solid transparent;
border-radius : 50% ;
background : #fff;
display : ;
}
.innerFrame {
height : 90% ;
width : 90% ;
box-shadow : 0 0 10px 2px #000;
z-index : 1 ;
}
.smallFrame {
height : 80% ;
width : 80% ;
z-index : 3 ;
}
.calibrate {
position : absolute ;
top : 0 ;
bottom : ;
right : 0 ;
left : 0 ;
margin : auto ;
height : 50% ;
width : 0 ;
transform-origin : 100% 100% ;
border-right : 1px solid #fff;
}
.indicators {
border-right : 1px solid #00f;
box-shadow : 0 0 5px 0px #000;
z-index : 2 ;
}
.knob {
position : absolute ;
top : 0 ;
bottom : 0 ;
right : 0 ;
left : 0 ;
margin : auto ;
height : 1.5% ;
width : 1.5% ;
border-radius : 50% ;
border : 3px solid #000;
background : #fff ;
z-index : 7 ;
}
.r0 { transform : rotateZ(0deg)}
.r6 { transform : rotateZ(6deg)}
.r12 { transform : rotateZ(12deg)}
.r18 { transform : rotateZ(18deg)}
.r24 { transform : rotateZ(24deg)}
.r30 { transform : rotateZ(30deg)}
.r36 { transform : rotateZ(36deg)}
.r42 { transform : rotateZ(42deg)}
.r48 { transform : rotateZ(48deg)}
.r54 { transform : rotateZ(54deg)}
.r60 { transform : rotateZ(60deg)}
.r66 { transform : rotateZ(66deg)}
.r72 { transform : rotateZ(72deg)}
.r78 { transform : rotateZ(78deg)}
.r84 { transform : rotateZ(84deg)}
.r90 { transform : rotateZ(90deg)}
.r96 { transform : rotateZ(96deg)}
.r102 { transform : rotateZ(102deg)}
.r108 { transform : rotateZ(108deg)}
.r114 { transform : rotateZ(114deg)}
.r120 { transform : rotateZ(120deg)}
.r126 { transform : rotateZ(126deg)}
.r132 { transform : rotateZ(132deg)}
.r138 { transform : rotateZ(138deg)}
.r144 { transform : rotateZ(144deg)}
.r150 { transform : rotateZ(150deg)}
.r156 { transform : rotateZ(156deg)}
.r162 { transform : rotateZ(162deg)}
.r168 { transform : rotateZ(168deg)}
.r174 { transform : rotateZ(174deg)}
.r180 { transform : rotateZ(180deg)}
.r186 { transform : rotateZ(186deg)}
.r192 { transform : rotateZ(192deg)}
.r198 { transform : rotateZ(198deg)}
.r204 { transform : rotateZ(204deg)}
.r210 { transform : rotateZ(210deg)}
.r216 { transform : rotateZ(216deg)}
.r222 { transform : rotateZ(222deg)}
.r228 { transform : rotateZ(228deg)}
.r234 { transform : rotateZ(234deg)}
.r240 { transform : rotateZ(240deg)}
.r246 { transform : rotateZ(246deg)}
.r252 { transform : rotateZ(252deg)}
.r258 { transform : rotateZ(258deg)}
.r264 { transform : rotateZ(264deg)}
.r270 { transform : rotateZ(270deg)}
.r276 { transform : rotateZ(276deg)}
.r282 { transform : rotateZ(282deg)}
.r288 { transform : rotateZ(288deg)}
.r294 { transform : rotateZ(294deg)}
.r300 { transform : rotateZ(300deg)}
.r306 { transform : rotateZ(306deg)}
.r312 { transform : rotateZ(312deg)}
.r318 { transform : rotateZ(318deg)}
.r324 { transform : rotateZ(324deg)}
.r330 { transform : rotateZ(330deg)}
.r336 { transform : rotateZ(336deg)}
.r342 { transform : rotateZ(342deg)}
.r348 { transform : rotateZ(348deg)}
.r354 { transform : rotateZ(354deg)}
.r358 { transform : rotateZ(360deg)}
</style>
<div class="containerX">
<div class="frame">
<div class="secHand"></div>
<div class="minHand">
<div class="miniCut"></div>
</div>
<div class="hourHand">
<div class="hourCut"></div>
</div>
<div class="innerFrame"></div>
<div class="smallFrame"></div>
<div class="knob"></div>
<div class="calibrate r0 indicators"></div>
<div class="calibrate r6"></div>
<div class="calibrate r12"></div>
<div class="calibrate r18"></div>
<div class="calibrate r24"></div>
<div class="calibrate r30 indicators"></div>
<div class="calibrate r36"></div>
<div class="calibrate r42"></div>
<div class="calibrate r48"></div>
<div class="calibrate r54"></div>
<div class="calibrate r60 indicators"></div>
<div class="calibrate r66"></div>
<div class="calibrate r72"></div>
<div class="calibrate r78"></div>
<div class="calibrate r84"></div>
<div class="calibrate r90 indicators"></div>
<div class="calibrate r96"></div>
<div class="calibrate r102"></div>
<div class="calibrate r108"></div>
<div class="calibrate r114"></div>
<div class="calibrate r120 indicators"></div>
<div class="calibrate r126"></div>
<div class="calibrate r132"></div>
<div class="calibrate r138"></div>
<div class="calibrate r144"></div>
<div class="calibrate r150 indicators"></div>
<div class="calibrate r156"></div>
<div class="calibrate r162"></div>
<div class="calibrate r168"></div>
<div class="calibrate r174"></div>
<div class="calibrate r180 indicators"></div>
<div class="calibrate r186"></div>
<div class="calibrate r192"></div>
<div class="calibrate r198"></div>
<div class="calibrate r204"></div>
<div class="calibrate r210 indicators"></div>
<div class="calibrate r216"></div>
<div class="calibrate r222"></div>
<div class="calibrate r228"></div>
<div class="calibrate r234"></div>
<div class="calibrate r240 indicators"></div>
<div class="calibrate r246"></div>
<div class="calibrate r252"></div>
<div class="calibrate r258"></div>
<div class="calibrate r264"></div>
<div class="calibrate r270 indicators"></div>
<div class="calibrate r276"></div>
<div class="calibrate r282"></div>
<div class="calibrate r288"></div>
<div class="calibrate r294"></div>
<div class="calibrate r300 indicators"></div>
<div class="calibrate r306"></div>
<div class="calibrate r312"></div>
<div class="calibrate r318"></div>
<div class="calibrate r324"></div>
<div class="calibrate r330 indicators"></div>
<div class="calibrate r336"></div>
<div class="calibrate r342"></div>
<div class="calibrate r348"></div>
<div class="calibrate r354"></div>
</div>
</div>
Как это работает
Это решение обновляет правила таблицы стилей для значений анимации ключевых кадров. Он не рассматривает размещение часового элемента в отдельных контейнерах, которые сами вращаются.
Использование таблицы стилей.
Теги стиля в HTML создают HTMLStyleElement в DOM. Содержимое элемента предоставляет исходный код CSS text .
Теги ссылок с атрибутом rel = "stylesheet" создают HTMLinkElement в DOM. Источник элемента предоставляет исходный код CSS text .
Исходный текст CSS, предоставленный элементом STYLE или LINK, анализируется для создания объекта CSSStyleSheet . Каждая созданная таблица стилей объект добавляется в массив document.styleSheets
.
Каждый объект таблицы стилей имеет свойство ownerNode
, которое ссылается на элемент HTMLE DOM, использованный для его создания.
Каждый объект таблицы стилей содержит массив объектов правил в виде массива в своем свойстве cssRules
.
Тип каждого объекта правила содержится в свойстве type . Значение type
для правила @keyframes
равно 7.
@keyframes
сами правила имеют свойство CSSRules
, содержащее список keyFrame объектов правил.
keyFrame
правила имеют свойства keyText
(не используется) и style
. Значение объекта стиля доступно только для чтения, но не заморожено - его свойства могут быть обновлены.
упрощения.
Метод findSheetById
использует значение id
элемента HTML, который сгенерировал объект таблицы стилей, для поиска объекта в массиве document.styleSheets
. Можно найти таблицу стилей, начиная с узла владельца, но в документации не хватает деталей. Другой альтернативой является обращение к таблице стилей путем жесткого кодирования ее индекса document.styleSheets
в программе.
Правила @keyframes
для часов, минут и секунд ищутся среди правил таблицы стилей верхнего уровня. Вложение их в правила @media
приведет к дальнейшим осложнениям.
Предполагается, что правила keyFrame
встречаются парами и индексируются индексами 0 и 1. Их значения keyText
("0%" и "100%") не проверяются.
Функция setClock
по умолчанию задает миллисекундный аргумент равным нулю, если не указан (как в примере). В действительности я бы предложил ввести значение времени в миллисекундах для повышения точности часов.
Онлайн эксперименты.
Для онлайн-тестирования вы можете попробовать вернуть document.styleSheets[0]
из findSheetById
или поместить элемент стиля с id в поле HTML онлайн-инструмента.