zemlan.in

Tweetimer

В воскресенье сел готовить выступление BeerJS Summit Minsk, но вместо текста и/или слайдов получился таймер для этого выступления (потому что в macOS до сих пор нет встроенного и потому что прокрастинация). Потом захотелось ужать его до минимального размера, so here I am, рассказываю как тратить время на то, что Uglify/Babel-minify делают за доли секунды…

В начале процесса усиленной минификации, таймер выглядел как-то так:

Базовый таймер
Базовый таймер

<style type="text/css">
 *{padding:0;margin:0}#d{width:100%;height:100%;background:#000}
 #t{color:#fff;font-size:70vh;font-family:sans-serif;mix-blend-mode:difference}
</style>
<body onload="((w,h,s,c,f,d)=>{
 s=new Date
 f=()=>{
  d=(new Date-s)/1000
  d=d<h?d:h
  c=h-parseInt(d)
  w.d.style.width=`${100*(h-d)/h}%`
  w.t.innerText=`${parseInt(c/60)}:`+`${c%60}`.padStart(2,0)
  c&&requestAnimationFrame(f)
 }
 f()
})(window,300)">
<div id=d>
<span id=t>

Код уже как-то минифицирован, например:

457 символов, великовато даже для новомодных твитов в 280

<style>

Больше трети таймера занимают стили

После этих манипуляций, таймер ужался до 390 символов

<body style=margin:0 onload="((w,h,s,c,f,d)=>{
 s=new Date
 f=()=>{
  d=(new Date-s)/1000
  d=d<h?d:h
  c=h-parseInt(d)
  w.d.style.width=`${100*(h-d)/h}%`
  w.t.innerText=`${parseInt(c/60)}:`+`${c%60}`.padStart(2,0)
  c&&requestAnimationFrame(f)
 }
 f()
})(window,300)">
<div style=height:100%;background:#000 id=d>
<span style="color:#fff;font:70vh futura;mix-blend-mode:difference" id=t>

Почему без CSS Transition?

Потому что Сафари (и, возможно, другие браузеры) могут приостанавливать transition’ы, если вкладка не в фокусе. Цифры таймера могут дотикать до 0:00, а бэкграунд — ещё будет «убывать»

JS

Вытащить ноль из кавычек додумался уже после отправки твита про таймер — JS сам его к строке приведёт

Уже кажется, что вот-вот влезет в твит… Но нет, 329 символа:

<body style=margin:0 onload="((w,h,s,d,f=()=>{
d=(new Date-s)/1e3
d=d<h?d:h
w.d.style.width=`${100*(h-d)/h}%`
d=h-d|0
w.t.innerText=`${d/60|0}:`+(d%60>9?``:0)+d%60
d&&setTimeout(f,30)
})=>f())(this,300,new Date)">
<div style=height:100%;background:#000 id=d>
<p style="color:#fff;font:70vh futura;mix-blend-mode:difference" id=t>

Режем красоту

Благодаря mix-blend-mode:difference, таймер отлично выглядит, но 26 символов (считая ; в стилях) — слишком большая цена для такой красоты

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

<div style=height:10%;background:#000 id=d>

можно было бы его сделать красным, чтобы срезать символ с цвета, но это слишком

Без особой красоты, таймер влезает в твит даже с переносами строк. Плюс, можно переименовать аргументы функции onload, чтобы хоть там была красота:

<body onload="((t,i,m,e,r=()=>{
e=(new Date-m)/1e3
e=e<i?e:i
t.d.style.width=`${100*(i-e)/i}%`
e=i-e|0
t.t.innerText=`${e/60|0}:`+(e%60>9?``:0)+e%60
e&&setTimeout(r,30)
})=>r())(this,300,new Date)">
<div style=height:10%;background:#000 id=d>
<p style="font:70vh futura" id=t>

Suddenly

Если попробовать запостить этот код в твиттер, сервис посчитает t.d.style за ссылку и вместо девяти символов насчитает 23. Так что придётся завернуть стаааайл в квадратные скобки: t.d['style']

Даже не убирая переносы строк, получилось 279 символа. Good (not-a-) job, me!

<body onload="((t,i,m,e,r=()=>{
e=(new Date-m)/1e3
e=e<i?e:i
t.d['style'].width=`${100*(i-e)/i}%`
e=i-e|0
t.t.innerText=`${e/60|0}:`+(e%60>9?``:0)+e%60
e&&setTimeout(r,30)
})=>r())(this,300,new Date)">
<div style=height:10%;background:#000 id=d>
<p style="font:70vh futura" id=t>

Минифицированный до 279 символов tweetimer
Минифицированный до 279 символов tweetimer