/* ==UserStyle==
@name Crisp up-scaled images for displays with 150% DPI scale factor (Firefox 74+)
@description Prevents blurry anti-aliased borders between picture sampling areas ("pixels").
@namespace myfonj
@version 1.0.1
@license CC0 - Public Domain
==/UserStyle== */
@-moz-document regexp(".*\\.(png|gif)(\\?.*)?(#.*)?$") {
/*
"DPI Zoom (scale) factor" can be obtained with JavaScript:
window.devicePixelRatio
for 150% DPI scale factor at page with 100% zoom level this should be 1.5
min zoom is 30 %
max zoom is 300 %
[ctrl] + [mouse wheel] modifies DPI consistently by +- 10 %.
[ctrl] + [+ / -] modifies DPI in prefefined values - powers of 10 % with two exceptions: 30, 50, *67*, 80, 90, 100, 110, 120, *133*, 150, 170, 200, 240, 300. Those exceptions and derived values [1] are not in scope of this stylesheet.
[1] in theory combining wheel and keyboard zoom one could possibly get 30, *33*, *37*, 40, *43*, *47*, 50 (...) zoom factors.
a.k.a. resolution value for media query
this file expects "normal" scale factor to be *150%*
what normally causes ugly blurry "scaled down" images
this style undoes that scale so that image pixels are mapped to physical pixels and anti-aliasing is suppressed
producing crisp scaled image in "100% zoom" (then it is mapped to 2×2 pixels) and controls resizing with `transform` to maintain crispness and predictable dimension in most zoom levels.
*/
/*
100% page zoom
1 = __ monitor scale × __ transform scale to "undo"
1 = 1.25 × 0.8
1 = 1.5 × 0.6666666666666
1 = 2 × 0.5
strangemesses:
?? __ page zoom at monitor set to __ scale is matched by `(resolution: __)`
!! 90% 100% 0.895522445440292259dppx
OK 50% 100% 0.5dppx
OK 100% 125% 1.25dppx
!! 100% 175% 1.76470595598220835dppx
centering crisp image of odd dimesion would produce unwanted "notch" from rounding
drawbacks:
- zooming is funky: apparently "zoom" is done by ajdusting DPI factor, so sometimes some of our rules hits
[width][height] = image fits viewport
*/
@media
(resolution: 0.75dppx),
(resolution: 0.8955223880597015dppx),
(resolution: 1.0526315789473684dppx),
(resolution: 1.2dppx),
(resolution: 1.3636363636363635dppx),
(resolution: 1.50dppx),
(resolution: 1.6666666666666667dppx),
(resolution: 1.8181818181818181dppx),
(resolution: 1.935483870967742dppx),
(resolution: 2.0689655172413794dppx),
(resolution: 2.00dppx),
(resolution: 2.2222222222222223dppx),
(resolution: 2.4dppx),
(resolution: 2.50dppx),
(resolution: 2.727272727272727dppx),
(resolution: 2.857142857142857dppx),
(resolution: 2.857142857142857dppx),
(resolution: 3.00dppx),
(resolution: 3.1578947368421053dppx),
(resolution: 3.3333333333333335dppx),
(resolution: 3.5294117647058822dppx),
(resolution: 3.3333333333333335dppx),
(resolution: 3.5294117647058822dppx), /* twice ?! */
(resolution: 3.75dppx),
(resolution: 4.00dppx),
(resolution: 4.285714285714286dppx),
(resolution: 4.615384615384615dppx)
{
html>body>img:only-child:not([width]):not([height]) {
image-rendering: var(--image-rendering, -moz-crisp-edges);
transform: scale(calc(var(--scale-to) / var(--dppx)));
transform-origin: top left;
margin: 0;
top: auto;
bottom: auto;
left: auto;
right: auto;
}
/*
debug
*/
html::after {
content: var(--dppx-debug) ' dppx; ' var(--zoom-debug) ' zoom; scale: ' var(--scale-to-debug) '×';
position: fixed;
top: 0;
right: 0;
color: #ccc;
background-color: rgba(0,0,0,0.5);
font-size: calc(1 / var(--dppx) * 1.9rem);
/*
this effectively cancels page zoom
so the physical text size remains the same
like using viewport units, but without viewport
accessibility warning
never ever do this
*/
}
}
@media (resolution: 0.75dppx) {
:root {
--zoom-debug: '50%';
--dppx: 0.75;
--dppx-debug: '0.75';
--scale-to: 0.0625;
--scale-to-debug: '0.0625';
--image-rendering: auto;
}
}
@media (resolution: 0.8955223880597015dppx) {
:root {
--zoom-debug: '60%';
--dppx: 0.8955223880597015;
--dppx-debug: '0.8955223880597015';
--scale-to: 0.125;
--scale-to-debug: '0.125';
--image-rendering: auto;
}
}
@media (resolution: 1.0526315789473684dppx) {
:root {
--zoom-debug: '70%';
--dppx: 1.0526315789473684;
--dppx-debug: '1.0526315789473684';
--scale-to: 0.25;
--scale-to-debug: '0.25';
--image-rendering: auto;
}
}
@media (resolution: 1.2dppx) {
:root {
--zoom-debug: '80%';
--dppx: 1.2;
--dppx-debug: '1.2';
--scale-to: 0.5;
--scale-to-debug: '0.5';
--image-rendering: auto;
}
}
@media (resolution: 1.2dppx) {
:root {
--zoom-debug: '80%';
--dppx: 1.2;
--dppx-debug: '1.2';
--scale-to: 0.5;
--scale-to-debug: '0.5';
--image-rendering: auto;
}
}
@media (resolution: 1.3636363636363635dppx) {
:root {
--zoom-debug: '90%';
--dppx: 1.3636363636363635;
--dppx-debug: '1.3636363636363635';
--scale-to: 1;
--scale-to-debug: '1';
}
}
@media (resolution: 1.50dppx) {
:root {
--zoom-debug: '100%';
--dppx: 1.50;
--dppx-debug: '1.50';
--scale-to: 2;
--scale-to-debug: '2';
}
}
@media (resolution: 1.6666666666666667dppx) {
:root {
--zoom-debug: '110%';
--dppx: 1.6666666666666667;
--dppx-debug: '1.6666666666666667';
--scale-to: 3;
--scale-to-debug: '3';
}
}
@media (resolution: 1.8181818181818181dppx) {
:root {
--zoom-debug: '120%';
--dppx: 1.8181818181818181;
--dppx-debug: '1.8181818181818181';
--scale-to: 4;
--scale-to-debug: '4';
}
}
@media (resolution: 1.935483870967742dppx) {
:root {
--zoom-debug: '130%';
--dppx: 1.935483870967742;
--dppx-debug: '1.935483870967742';
--scale-to: 5;
--scale-to-debug: '5';
}
}
@media (resolution: 2.00dppx) {
:root {
--zoom-debug: '133%';
--dppx: 2.00;
--dppx-debug: '2.00';
--scale-to: 6;
--scale-to-debug: '6';
}
}
@media (resolution: 2.0689655172413794dppx) {
:root {
--zoom-debug: '140%';
--dppx: 2.0689655172413794;
--dppx-debug: '2.0689655172413794';
--scale-to: 7;
--scale-to-debug: '7';
}
}
@media (resolution: 2.2222222222222223dppx) {
:root {
--zoom-debug: '150%';
--dppx: 2.2222222222222223;
--dppx-debug: '2.2222222222222223';
--scale-to: 8;
--scale-to-debug: '8';
}
}
@media (resolution: 2.4dppx) {
:root {
--zoom-debug: '160%';
--dppx: 2.4;
--dppx-debug: '2.4';
--scale-to: 9;
--scale-to-debug: '9';
}
}
@media (resolution: 2.50dppx) {
:root {
--zoom-debug: '170%';
--dppx: 2.50;
--dppx-debug: '2.50';
--scale-to: 10;
--scale-to-debug: '10';
}
}
@media (resolution: 2.727272727272727dppx) {
:root {
--zoom-debug: '180%';
--dppx: 2.727272727272727;
--dppx-debug: '2.727272727272727';
--scale-to: 11;
--scale-to-debug: '11';
}
}
@media (resolution: 2.857142857142857dppx) {
:root {
--zoom-debug: '190%';
--dppx: 2.857142857142857;
--dppx-debug: '2.857142857142857';
--scale-to: 12;
--scale-to-debug: '12';
}
}
@media (resolution: 3.00dppx) {
:root {
--zoom-debug: '200%';
--dppx: 3.00;
--dppx-debug: '3.00';
--scale-to: 13;
--scale-to-debug: '13';
}
}
@media (resolution: 3.1578947368421053dppx) {
:root {
--zoom-debug: '210%';
--dppx: 3.1578947368421053;
--dppx-debug: '3.1578947368421053';
--scale-to: 14;
--scale-to-debug: '14';
}
}
@media (resolution: 3.3333333333333335dppx) {
:root {
--zoom-debug: '220%';
--dppx: 3.3333333333333335;
--dppx-debug: '3.3333333333333335';
--scale-to: 15;
--scale-to-debug: '15';
}
}
@media (resolution: 3.5294117647058822dppx) {
:root {
--zoom-debug: '230% or 240%';
/*
for some mysterious reason both zoom levels matches this resolution
*/
--dppx: 3.5294117647058822;
--dppx-debug: '3.5294117647058822';
--scale-to: 16;
--scale-to-debug: '16';
}
}
@media (resolution: 3.75dppx) {
:root {
--zoom-debug: '250%';
--dppx: 3.75;
--dppx-debug: '3.75';
--scale-to: 17;
--scale-to-debug: '17';
}
}
@media (resolution: 4.00dppx) {
:root {
--zoom-debug: '260% or 270%';
/*
for some mysterious reason both zoom levels matches this resolution
*/
--dppx: 4.00;
--dppx-debug: '4.00';
--scale-to: 18;
--scale-to-debug: '18';
}
}
@media (resolution: 4.285714285714286dppx) {
:root {
--zoom-debug: '280% or 290%';
/*
for some mysterious reason both zoom levels matches this resolution
*/
--dppx: 4.285714285714286;
--dppx-debug: '4.285714285714286';
--scale-to: 19;
--scale-to-debug: '19';
}
}
@media (resolution: 4.615384615384615dppx) {
:root {
--zoom-debug: '300%';
--dppx: 4.615384615384615;
--dppx-debug: '4.615384615384615';
--scale-to: 20;
--scale-to-debug: '20';
}
}
}