Edit: I just remembered I've been using an extension called "Hacker News Enhancement Suite" to enhance the layout of HN, and after disabling it, Dark Reader worked so I think that extension was somehow interfering with Dark Reader.
I use "Hacker News Readable Dark" under Stylus and this site looks fantastic.
If anyone knows a similar solution that doesn't require such an extreme, I'd like to hear about it..
Anyway, my vague understanding of what is does is that it inverts all colors on the wrong side of a user-configurable brightness threshold (e.g. backgrounds that are too bright are inverted, and text that is too dark is inverted). This can make website colorschemes quite different, but most of the websites I visit regularly are still still readable, and often still reasonably nice-looking, despite having inverted colors.
The relevant part of my config file looks like this:
# This requests the dark version of the website if it is available. Generally when this
# works, I guess brightness-based the color inversion doesn't happen.
c.colors.webpage.preferred_color_scheme = 'dark'
c.colors.webpage.darkmode.algorithm = 'lightness-cielab'
c.colors.webpage.darkmode.contrast = 0.0
c.colors.webpage.darkmode.enabled = True
c.colors.webpage.darkmode.grayscale.all = False
c.colors.webpage.darkmode.grayscale.images = 0.0
c.colors.webpage.darkmode.policy.images = 'smart'
c.colors.webpage.darkmode.policy.page = 'smart'
c.colors.webpage.darkmode.threshold.background = 128
c.colors.webpage.darkmode.threshold.text = 128
I haven't spent any time tweaking the threshold values, but maybe some tweaking would make it even better.Like, there is simply no way that is not a solvable issue.
Where Dark Reader is full-featured, mine is minimal. It adds a translucent tinted div overlay on every page, with mix-blend-mode:multiply to make the text come out a little sharper. No themes or querying page elements.
You can audit the code yourself if you want, it's only 58 lines of JS across 2 files:
// content.js (this runs on every page):
'use strict';
const C=chrome, d=document.createElement('div'),
update=(o={})=>{
if('tog' in o){d.style.height = (o.tog.newValue | o.tog)+'00%';}
if('color' in o){d.style.backgroundColor = o.color.newValue || o.color;}
};
d.style='mix-blend-mode:multiply; z-index:2147483647; position:fixed; width:100%; top:0; right:0; pointer-events:none;';
document.documentElement.insertBefore(d, document.documentElement.firstChild);
C.storage.local.get(null, update);
C.runtime.onMessage.addListener(update);
C.storage.onChanged.addListener(update);
// popup.js:
'use strict';
let XY=[150,40];
const C=chrome, S=C.storage.local,
send=x=>C.tabs.query({active:true,currentWindow:true}, t=>C.tabs.sendMessage(t[0].id, x)),
torgba=x=>`rgba(${x[0]}, ${x[1]}, ${x[2]}, ${x[3]/255})`,
dropper=(x,y)=>torgba(c.getImageData(x,y,1,1).data),
target=(x,y)=>{c.fillStyle = 'black'; c.beginPath(); c.arc(x,y,30,0,Math.PI*2,true); c.stroke();},
touch_xy=t=>{const r=c.canvas.getBoundingClientRect(), f=(x,ox,r)=>Math.floor(Math.min(Math.max(x,ox+1),r-1)-ox);
return[f(t.pageX, r.left, r.right), f(t.pageY, r.top, r.bottom)];},
init_c=()=>{
c.clearRect(0,0,c.canvas.width,c.canvas.height);
c.canvas.style.backgroundColor='white';
const g1=c.createLinearGradient(0, 0, c.canvas.width, 0), // horiz, hue
g2=c.createLinearGradient(0, 0, 0, c.canvas.height); // vert, lightness
g1.addColorStop(0.2,'rgba(255,120,120,0)');
g1.addColorStop(1,'rgba(255,130,70,0.99)');
g2.addColorStop(0,'rgba(0,0,0,0)');
g2.addColorStop(1,'rgba(0,0,0,0.8)');
c.fillStyle = g1; c.fillRect(0,0,c.canvas.width,c.canvas.height);
c.fillStyle = g2; c.fillRect(0,0,c.canvas.width,c.canvas.height);},
xy_send=(xy)=>{init_c(); target(...xy); send({xy, color:dropper(...xy)});},
xy_save=(xy)=>{init_c(); target(...xy); S.set({xy, color:dropper(...xy)});},
c=document.getElementById('c').getContext('2d'),
tog=document.getElementById('tog');
window.addEventListener('load',()=>{
S.get(null, o=>{
if('tog' in o){tog.checked = o.tog;} else {S.set({tog:tog.checked});}
if('xy' in o){init_c(); target(...o.xy); XY=o.xy;} else {S.set({xy:XY});} // color's xy coords in canvas
if(!('color' in o)){S.set({color:dropper(...XY)});} // hardcoded default xy location
});
tog.addEventListener('change', x=>{S.set({tog:tog.checked});});
c.canvas.addEventListener('mousemove', x=>{if(x.buttons!==1){return;} xy_send([x.offsetX, x.offsetY]);});
c.canvas.addEventListener('mouseup', x=>xy_save([x.offsetX, x.offsetY]));
c.canvas.addEventListener('touchmove', x=>xy_send(touch_xy(x.targetTouches[0])));
c.canvas.addEventListener('touchend', x=>xy_save(touch_xy(x.changedTouches[0])));
});
window.addEventListener('keydown', e=>{
if(e.key==='x'){tog.checked = !tog.checked; S.set({tog:tog.checked});}
});
Full source: https://gitlab.com/hoosieree/chrome-extension-obscuraI feel like during the day most things are bright/cool with darkness as the contrast. Text on paper. Also as much as dark mode has become an option, it's impossible to go an entire day without experiencing a light theme and the switching of light to dark or dark to light for me is worse than whatever problems each theme has. Point being it's easier to only use light than only use dark.
Anyway dark mode without red tint isn't really helping with the blue light problem? Especially if the media you're looking at is mixed with e.g. images of daylight.
Sometimes it leaves black-on-dark for icons and such, but that's negligible, and definitely a good trade-off to my eyes being drained.
Side note: Maps is surprisingly good with Dark Reader!
More importantly installed the Dark Reader extension (https://darkreader.org). This one is incredible: it's much nicer to browser the Web in dark mode than to make page reddish. I now enable Dark Reader at all time (day and night) and can't stand the screen of my coworkers (so dazzling).
Idem for my Android device.
The only app/webpage I don' apply dark mode/reader to is Google Maps. For now…