creepjs
creepjs copied to clipboard
create screen test and capture css media fingerprint
https://developer.mozilla.org/en-US/docs/Web/CSS/@media
- [x] - devicePixelRatio
- [x] - matchMedia
- [x] - @media: https://jsfiddle.net/w8qxu1p2/1/
- [x] - detect screen via
getComputedStyle: https://jsfiddle.net/jrnca3wh/ - [x]
@importcan access media queries: https://jsfiddle.net/s8xcg0ou/3/
matchMedia(`(min-device-height:${screen.height}px)`).matches
matchMedia(`(min-device-width:${screen.width}px)`).matches
matchMedia(`(max-device-height:${screen.height}px)`).matches
matchMedia(`(max-device-width:${screen.width}px)`).matches
matchMedia(`(device-height:${screen.height}px)`).matches
matchMedia(`(device-width:${screen.width}px)`).matches
https://abrahamjuliot.github.io/creepjs/tests/screen.html
orientation and viewport are undefined - FF nightly 86, and yes my inner is square :)

tzp has a scrollbar hence viewport is not 1000x1000

https://jsfiddle.net/873kspn4/1/
FF nightly 86 RFP off = prefersColorScheme: "", prefersReducedMotion: "" FF nightly 86 RFP on = prefersColorScheme: "", prefersReducedMotion: "no-preference"
What does import gain over just a straight css (besides the fact that JS can read it quickly)
viewport
I'm now discovering, FF has visualViewport behind the flag dom.visualviewport.enabled. This should now yield the unsupported label if both dimensions are undefined.
orientation
Oops, that's a bug I left in there. Fixed.
@import
@media and @import are pretty much the same. I might add this later to test if Chromium's proposed privacy budget covers both and matchMedia.
https://bugzilla.mozilla.org/show_bug.cgi?id=1579584#c5 and subsequent comments
I've been letting android tests lapse. Anyway, if I read that right, then we can detect if dynamic toolbar is enabled? I should make a test: i.e if enabled 100vh - inner = toolbar height ... if disabled 100vh - inner = zero
wanna test that for me?
I do not know what you mean by @media and by MediaQueryList. What is the difference? Which one is @matchmedia if any?
I have questions. Using Firefox Nightly on Android. RFP off on the left, RFP on on the right
screen test
- Both
- why the fake screen returns
- why is the height different in visualViewport
- note: how are you getting this. In TZP we use a binary search in matchmedia to get subpixels (decimals) for measurements (screen, inner etc) which show up when the devicePixelRatio != 1 = almost always on android = entropy galore!!
- RFP on
- why undefined for heights
- why is aspect ratio fake? in TZP with RFP on this is all
portrait(all 8 values). What are you using to calculate16/9or6/13etc - FWIW I don't think it's worthwhile returning e.g.
16/9when that entropy is already in the width + height measurements: but maybe you're trying to catch something out here, like an extension lie? Please explain yourself young man, or you won't get any pudding.

creepy test
- green boxes on RFP=on

100vh - inner = toolbar height ... if disabled 100vh - inner = zero
This seems the same as obtaining 100vh and inner (the difference is only unspoken). I'm not sure how 100vh were obtained to verify this, but document.documentElement.clientHeight should match window.innerHeight. I don't have a dynamic tooldbar (?) on my devices.
const hasToolbar = !!(document.documentElement.clientHeight - window.innerHeight)
MediaQueryList and matchMedia are the same. MediaQueryList is the object returned.
I don't have a dynamic toolbar
Android > Firefox > Settings > General > Customize > Scroll to hide toolbar (default = on)
screen test
- fake screen: if a result is undefined, the screen is presumed fake. I added the output and limited the fake test to screen (the test just compares screen with matchMedia). I'm realizing this returns a false positive if the matchMedia only matches a float, but I've only noticed this in an android emulator (I presume it's the same in a virtual machine) and in those context, the screen size is technically fake. Are you getting a fake screen on an actual android device?
- visualViewport: this returns a float height on FF Android. I'm now using Math.round in the template output, but the floating point might provide some entropy in a fingerprint.
const vViewport = 'visualViewport' in window ? visualViewport : { }
const { width: viewportWidth, height: viewportHeight } = vViewport
console.log(`${Math.round(viewportWidth)} x ${Math.round(viewportHeight)}`)
- undefined heights/aspect ratio: since I'm searching for an integer (up to 10000px), if there is no match it's undefined.
- 16/9 aspect ratio: this is really not that useful since width height reveals the same (aspect-ratio is only unspoken)
// gcd is based on https://stackoverflow.com/a/1186465
const gcd = (a, b) => b == 0 ? a : gcd(b, a%b)
const { innerWidth, innerHeight } = window
const { width: screenWidth, height: screenHeight } = screen
const ratio = gcd(innerWidth, innerHeight)
const screenRatio = gcd(screenWidth, screenHeight)
const aspectRatio = `${innerWidth/ratio}/${innerHeight/ratio}`
const deviceAspectRatio = `${screenWidth/screenRatio}/${screenHeight/screenRatio}`
/*css*/
@media (aspect-ratio: ${aspectRatio}) {
body {--viewport-aspect-ratio: ${aspectRatio};}
}
@media (device-aspect-ratio: ${deviceAspectRatio}) {
body {--device-aspect-ratio: ${deviceAspectRatio};}
}
dynamic toolbar
I'm not sure there is practical method to detect this since the toolbar is only hidden when/if the user scrolls.
creepy test
I use an iframe for the screen metrics on creep, and as far as I know RFP restricts screen metrics in iframes.
what are you using for getting vunits?
function get_vunits() {
let div, vh1, vw1
div = document.createElement("vunits")
div.style.height = "100vh"
div.style.width = "100vw"
div.style.maxHeight = "none"
div.style.boxSizing = "content-box"
document.body.appendChild(div)
vw1 = div.clientWidth
vh1 = div.clientHeight
document.body.removeChild(div)
console.log(vw1 +" x "+ vh1) // I get 0x0 .. approx 2ms
function vh(v) {
let h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
return (v * h) / 100;
}
function vw(v) {
let w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
return (v * w) / 100;
}
function vmin(v) {
return Math.min(vh(v), vw(v));
}
function vmax(v) {
return Math.max(vh(v), vw(v));
}
console.log(vw(100), Math.max(document.documentElement.clientWidth, window.innerWidth || 0));
console.log(vh(100), Math.max(document.documentElement.clientHeight, window.innerHeight || 0));
console.log(vmin(100));
console.log(vmax(100)); // approx 1 or 2 ms
}
Are you getting a fake screen on an actual android device
Yes. The screen shots are from my realsies android
but the floating point might provide some entropy in a fingerprint
entropy is good: we get this (decimals) on TZP when devicePixelRatio is not 1. Just wondering why the value changed
edit: there is also this: https://devicepixelratio.glitch.me/
PS: I have been looking at expanding other measuring methods in the screen section for some time
- v units was one on my list
- visualViewport was also noted (and there's a change in FF coming to allow subpixel measurements: not sure if VViewport or just inner etc)
- I wanted to look at that glitchme code
- now you've listed
- import
- computedStyle
- @media (I'm still not sure what that means)
- matchMedia object
- using an iframe
- I also already have an element that is set to 100 width/height that I use for when you do the FS test
Would be nice to list get all this into TZP
vh units
I use document.documentElement.clientHeight. It's the same as above. Where v is 100 and h is clientHeight, (v * h) / 100 yields the same result as h
TZP when devicePixelRatio is not 1
That's sounds awesome. I'll take a look and try it out.
^^ big edit 3 posts up :)
edit: and intersection observer which I have a poc lying around
TZP when devicePixelRatio is not 1
That's sounds awesome. I'll take a look and try it out.
the decimal places happen because of the real devicePixelRatio, not because I factor in the reported dPR
Here is my realsies android with RFP on
- it hides dPR as 1, in reality it is
2.60..something. Note my PoC that exposes an almost real value - I am not using that dPR PoC at all, but note the two matchMedia ~~
min~~ height results have decimal places - revealing entropy and the existence of subpixels