Skip to content

Instantly share code, notes, and snippets.

@myfonj
Last active June 22, 2020 15:19
Show Gist options
  • Save myfonj/a84a069aec26f2e1875125a7899d39d0 to your computer and use it in GitHub Desktop.
Save myfonj/a84a069aec26f2e1875125a7899d39d0 to your computer and use it in GitHub Desktop.
Crisp Scaled Images
/* ==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== */
/*
"DPI Zoom (scale) factor" can be obtained with JavaScript:
window.devicePixelRatio
For 150% DPI scale factor at page with reported 100% zoom level this should be 1.5.
By default, image zoom (as well as full page zoom) is implemented as "shrinking viewport and setting modifying DPPX so that resulting outcome
(This does not apply when
Zoom is between 30% min and 300% max, clamped.
How to zoom:
[ctrl][scroll wheel up] adds 10% zoom.
[ctrl][scroll wheel down] subtracts 10% zoom.
[ctrl][+] [ctrl][-] as well as clicking "+"
[click "+" in toolbar]
```
30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 210 220 230 240 250 260 270 280 290 300
30 50 *67* 80 90 100 110 120 *133* 150 170 200 240 300
```
-- is replaced by 67% so resulting DPPX is exactly 1,
-- is replaced by 133% so resulting DPPX is exactly 2.
From those two values you can get any ?3% or ?7%
Browser page zoom | dppx for display with DPI zoom factor 150%
30 | 0.45112781954887216
33 | 0.49586776859504134
37 | 0.5555555555555556
40 | 0.6
43 | 0.6451612903225806
47 | 0.7058823529411765
50 | 0.75
53 | 0.8
57 | 0.8571428571428571
60 | 0.8955223880597015
63 | 0.9523809523809523
67 | 1.0
70 | 1.052631578947368
73 | 1.0909090909090908
77 | 1.1538461538461537
80 | 1.2
83 | 1.25
87 | 1.3043478260869565
90 | 1.3636363636363635
93 | 1.3953488372093024
97 | 1.4634146341463414
100 | 1.5
103 | 1.5384615384615385
107 | 1.6216216216216217
110 | 1.6666666666666667
113 | 1.7142857142857142
117 | 1.7647058823529411
120 | 1.8181818181818181
123 | 1.8181818181818181
127 | 1.935483870967742
130 | 1.935483870967742
133 | 2.0
137 | 2.0689655172413794
140 | 2.0689655172413794
143 | 2.142857142857143
147 | 2.2222222222222223
150 | 2.2222222222222223
153 | 2.3076923076923075
157 | 2.4
160 | 2.4
163 | 2.4
167 | 2.5
170 | 2.5
173 | 2.608695652173913
177 | 2.608695652173913
180 | 2.727272727272727
183 | 2.727272727272727
187 | 2.857142857142857
190 | 2.857142857142857
193 | 2.857142857142857
197 | 3.0
200 | 3.0
203 | 3.0
207 | 3.1578947368421053
210 | 3.1578947368421053
213 | 3.1578947368421053
217 | 3.3333333333333335
220 | 3.3333333333333335
223 | 3.3333333333333335
227 | 3.3333333333333335
230 | 3.5294117647058822
233 | 3.5294117647058822
237 | 3.5294117647058822
240 | 3.5294117647058822
243 | 3.75
247 | 3.75
250 | 3.75
253 | 3.75
257 | 3.75
260 | 4.0
263 | 4.0
267 | 4.0
270 | 4.0
273 | 4.0
277 | 4.285714285714286
280 | 4.285714285714286
283 | 4.285714285714286
287 | 4.285714285714286
290 | 4.285714285714286
293 | 4.285714285714286
297 | 4.615384615384615
300 | 4.615384615384615
Browser page zoom | dppx for display with DPI zoom factor 100%
30 | 0.3
33 | 0.32967032967032966
37 | 0.37037037037037035
40 | 0.4
43 | 0.42857142857142855
47 | 0.46875
50 | 0.5
53 | 0.5309734513274337
57 | 0.5714285714285714
60 | 0.6
63 | 0.631578947368421
67 | 0.6666666666666666
70 | 0.6976744186046512
73 | 0.7317073170731707
77 | 0.7692307692307693
80 | 0.8
83 | 0.8333333333333334
87 | 0.8695652173913043
90 | 0.8955223880597015
93 | 0.9230769230769231
97 | 0.967741935483871
100 | 1.0
103 | 1.0344827586206897
107 | 1.0714285714285714
110 | 1.0909090909090908
113 | 1.1320754716981132
117 | 1.1764705882352942
120 | 1.2
123 | 1.2244897959183674
127 | 1.2765957446808511
130 | 1.3043478260869565
133 | 1.3333333333333333
137 | 1.3636363636363635
140 | 1.3953488372093024
143 | 1.4285714285714286
147 | 1.4634146341463414
150 | 1.5
153 | 1.5384615384615385
157 | 1.5789473684210527
160 | 1.5789473684210527
163 | 1.6216216216216217
167 | 1.6666666666666667
170 | 1.7142857142857142
173 | 1.7142857142857142
177 | 1.7647058823529411
180 | 1.8181818181818181
183 | 1.8181818181818181
187 | 1.875
190 | 1.875
193 | 1.935483870967742
197 | 2.0
200 | 2.0
203 | 2.0
207 | 2.0689655172413794
210 | 2.0689655172413794
213 | 2.142857142857143
217 | 2.142857142857143
220 | 2.2222222222222223
223 | 2.2222222222222223
227 | 2.3076923076923075
230 | 2.3076923076923075
233 | 2.3076923076923075
237 | 2.4
240 | 2.4
243 | 2.4
247 | 2.5
250 | 2.5
253 | 2.5
257 | 2.608695652173913
260 | 2.608695652173913
263 | 2.608695652173913
267 | 2.727272727272727
270 | 2.727272727272727
273 | 2.727272727272727
277 | 2.727272727272727
280 | 2.857142857142857
283 | 2.857142857142857
287 | 2.857142857142857
290 | 2.857142857142857
293 | 3.0
297 | 3.0
300 | 3.0
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
*/
@-moz-document regexp("^[^?#]+\\.(png|gif)(\\?[^#]*)?(#.*)?|#crisp!$") {
@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';
}
}
}
/* ==UserStyle==
@name Crisp image zoom at 150% DPI scale factor displays (Firefox 74+)
@description Prevents blurry anti-aliased borders between picture sampling areas ("pixels") by stretching them so they precisely match (multiples of) physical display points
@namespace myfonj
@version 2.1.1
@license CC0 - Public Domain
==/UserStyle== */
@-moz-document regexp("^[^?#]+\\.(png|gif|ico)(\\?[^#]*)?(#.*)?|#crisp$") {
html>body>img:only-child:not([width]):not([height]) {
image-rendering: var(--i, -moz-crisp-edges);
transform: scale(calc(var(--s) / var(--d)));
transform-origin: top left;
top: 0;
bottom: auto;
left: 0;
right: auto;
margin: 0;
}
@media(resolution:0.45112781954887216dppx){:root{--d:0.45112781954887216;--s:calc(1 / 64);--i:auto;}}/*·F← --z:'←30'; */
@media(resolution:0.49586776859504134dppx){:root{--d:0.49586776859504134;--s:calc(1 / 64);--i:auto;}}/*·F· --z:'33'; */
@media(resolution:0.55555555555555560dppx){:root{--d:0.55555555555555560;--s:calc(1 / 64);--i:auto;}}/*·F· --z:'37'; */
@media(resolution:0.60000000000000000dppx){:root{--d:0.60000000000000000;--s:calc(1 / 32);--i:auto;}}/*·E← --z:'←40'; */
@media(resolution:0.64516129032258060dppx){:root{--d:0.64516129032258060;--s:calc(1 / 32);--i:auto;}}/*·E· --z:'43'; */
@media(resolution:0.70588235294117650dppx){:root{--d:0.70588235294117650;--s:calc(1 / 32);--i:auto;}}/*·E· --z:'47'; */
@media(resolution:0.75000000000000000dppx){:root{--d:0.75000000000000000;--s:calc(1 / 16);--i:auto;}}/*·D← --z:'←50'; */
@media(resolution:0.80000000000000000dppx){:root{--d:0.80000000000000000;--s:calc(1 / 16);--i:auto;}}/*·D· --z:'53'; */
@media(resolution:0.85714285714285710dppx){:root{--d:0.85714285714285710;--s:calc(1 / 16);--i:auto;}}/*·D· --z:'57'; */
@media(resolution:0.89552238805970150dppx){:root{--d:0.89552238805970150;--s:calc(1 / 8 );--i:auto;}}/*·C← --z:'←60'; */
@media(resolution:0.95238095238095230dppx){:root{--d:0.95238095238095230;--s:calc(1 / 8 );--i:auto;}}/*·C· --z:'63'; */
@media(resolution:1.00000000000000000dppx){:root{--d:1.00000000000000000;--s:calc(1 / 8 );--i:auto;}}/*·C· --z:'67'; */
@media(resolution:1.05263157894736800dppx){:root{--d:1.05263157894736800;--s:calc(1 / 4 );--i:auto;}}/*·B← --z:'←70'; */
@media(resolution:1.09090909090909080dppx){:root{--d:1.09090909090909080;--s:calc(1 / 4 );--i:auto;}}/*·B· --z:'73'; */
@media(resolution:1.15384615384615370dppx){:root{--d:1.15384615384615370;--s:calc(1 / 4 );--i:auto;}}/*·B· --z:'77'; */
@media(resolution:1.20000000000000000dppx){:root{--d:1.20000000000000000;--s:calc(1 / 2 );--i:auto;}}/*·A← --z:'←80'; */
@media(resolution:1.25000000000000000dppx){:root{--d:1.25000000000000000;--s:calc(1 / 2 );--i:auto;}}/*·A· --z:'83'; */
@media(resolution:1.30434782608695650dppx){:root{--d:1.30434782608695650;--s:calc(1 / 2 );--i:auto;}}/*·A· --z:'87'; */
@media(resolution:1.36363636363636350dppx){:root{--d:1.36363636363636350;--s:1;}} /*···a← --z:'←90'; */
@media(resolution:1.39534883720930240dppx){:root{--d:1.39534883720930240;--s:1;}} /*···a· --z:'93'; */
@media(resolution:1.46341463414634140dppx){:root{--d:1.46341463414634140;--s:1;}} /*···a· --z:'97'; */
@media(resolution:1.50000000000000000dppx){:root{--d:1.50000000000000000;--s:2;}} /*···b← --z:'←100'; */
@media(resolution:1.53846153846153850dppx){:root{--d:1.53846153846153850;--s:2;}} /*···b· --z:'103'; */
@media(resolution:1.62162162162162170dppx){:root{--d:1.62162162162162170;--s:2;}} /*···b· --z:'107'; */
@media(resolution:1.66666666666666670dppx){:root{--d:1.66666666666666670;--s:3;}} /*···c← --z:'←110'; */
@media(resolution:1.71428571428571420dppx){:root{--d:1.71428571428571420;--s:3;}} /*···c· --z:'113'; */
@media(resolution:1.76470588235294110dppx){:root{--d:1.76470588235294110;--s:3;}} /*···c· --z:'117'; */
@media(resolution:1.81818181818181810dppx){:root{--d:1.81818181818181810;--s:4;}} /*···d← --z:'←120|123'; */
@media(resolution:1.93548387096774200dppx){:root{--d:1.93548387096774200;--s:5;}} /*···e← --z:'127|←130'; */
@media(resolution:2.00000000000000000dppx){:root{--d:2.00000000000000000;--s:5;}} /*···e· --z:'133'; */
@media(resolution:2.06896551724137940dppx){:root{--d:2.06896551724137940;--s:6;}} /*···f← --z:'137|←140'; */
@media(resolution:2.14285714285714300dppx){:root{--d:2.14285714285714300;--s:6;}} /*···f· --z:'143'; */
@media(resolution:2.22222222222222230dppx){:root{--d:2.22222222222222230;--s:8;}} /*···g← --z:'147|←150'; */
@media(resolution:2.30769230769230750dppx){:root{--d:2.30769230769230750;--s:8;}} /*···g· --z:'153'; */
@media(resolution:2.40000000000000000dppx){:root{--d:2.40000000000000000;--s:8;}} /*···h← --z:'157|←160|163'; */
@media(resolution:2.50000000000000000dppx){:root{--d:2.50000000000000000;--s:10;}}/*···i← --z:'167|←170'; */
@media(resolution:2.60869565217391300dppx){:root{--d:2.60869565217391300;--s:10;}}/*···i· --z:'173|177'; */
@media(resolution:2.72727272727272700dppx){:root{--d:2.72727272727272700;--s:12;}}/*···j← --z:'←180|183'; */
@media(resolution:2.85714285714285700dppx){:root{--d:2.85714285714285700;--s:14;}}/*···k← --z:'187|←190|193'; */
@media(resolution:3.00000000000000000dppx){:root{--d:3.00000000000000000;--s:16;}}/*···l← --z:'197|←200|203'; */
@media(resolution:3.15789473684210530dppx){:root{--d:3.15789473684210530;--s:18;}}/*···m← --z:'207|←210|213'; */
@media(resolution:3.33333333333333350dppx){:root{--d:3.33333333333333350;--s:20;}}/*···n← --z:'217|←220|223|227'; */
@media(resolution:3.52941176470588220dppx){:root{--d:3.52941176470588220;--s:22;}}/*·o|p← --z:'←230|233|237|240'; */
@media(resolution:3.75000000000000000dppx){:root{--d:3.75000000000000000;--s:24;}}/*···q← --z:'243|247|←250|253|257'; */
@media(resolution:4.00000000000000000dppx){:root{--d:4.00000000000000000;--s:26;}}/*·r|s← --z:'←260|263|267|←270|273'; */
@media(resolution:4.28571428571428600dppx){:root{--d:4.28571428571428600;--s:28;}}/*·t|u← --z:'277|←280|283|287|←290|293'; */
@media(resolution:4.61538461538461500dppx){:root{--d:4.61538461538461500;--s:30;}}/*···v← --z:'297|←300'; */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment