Skip to content

Instantly share code, notes, and snippets.

@Blumed
Last active July 19, 2025 01:55
Show Gist options
  • Save Blumed/47b10fb4dccc2cb430c679868d2a9e0e to your computer and use it in GitHub Desktop.
Save Blumed/47b10fb4dccc2cb430c679868d2a9e0e to your computer and use it in GitHub Desktop.
pixel to rem converter bookmarklet

Pixel to Rem Converter

Features:

  • It reads the current pages root pixel size and unit size calculations will be based off of it
  • You can edit the root pixel size if you would like and all calculations of unit sizes will change accordingly
  • Updating the pixel value will update the rem value automatically
  • Updating the rem value will update the pixel value automatically
  • Using the copy buttons will append the unit name to the end of the value for you ex. 16px or 1.5rem
  • Using up and down arrow keys will increment and decrement values in each input field
  • UI is all tabable so you don't need a mouse to use it
  • Autofocus on pixel input when UI initializes
  • UI is themeable. Feel free to change colors around with ease!

This was a fairly quick and dirty bookmarklet I threw together one evening. The styles could be way more defensive so strong page styles won't mess with UI. I will for sure come back to it and harden the styles up at some point.

Known Issues:

  • If you change the root the value calculation depending on what the root value becomes can make the pixel value a crazy number. Changing the root without changing the pixel value is a bit useless so I assume you would do this anyway which fixes the calculation immediately.

Created with ❤️ using https://make-bookmarklets.com

const bookmarklet = { name: "bookmakrlet__pixel-to-rem", version: "1.5" };
try {
// Create unique names
const name = {
wrapper: `${bookmarklet.name}__wrapper`,
close: `${bookmarklet.name}__close`,
rootLabel: `${bookmarklet.name}__root-label`,
rootInput: `${bookmarklet.name}__root-input`,
pixelLabel: `${bookmarklet.name}__pixel-label`,
pixelInput: `${bookmarklet.name}__pixel-input`,
pixelCopy: `${bookmarklet.name}}__pixel-copy`,
remLabel: `${bookmarklet.name}__rem-label`,
remInput: `${bookmarklet.name}__rem-input`,
remCopy: `${bookmarklet.name}__rem-copy`
};
// Helper functions
const createElement = (type, className, attributes = {}) => {
const element = document.createElement(type);
element.className = className;
Object.entries(attributes).forEach(([key, value]) => element.setAttribute(key, value));
return element;
};
const copyText = text => {
try { navigator.clipboard.writeText(text); }
catch (err) { console.error("Failed to copy:", err); }
};
// Create container
const container = createElement("div", name.wrapper);
document.body.appendChild(container);
// Create close button
const close = createElement("button", name.close, { type: "button" });
close.textContent = "Close";
close.onclick = () => container.remove();
container.appendChild(close);
// SVG icon
const copyIcon = '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z"/></svg>';
// Create input groups
const createInputGroup = (labelText, inputId, copyId, copyTitle) => {
const label = createElement("label", inputId.replace('input', 'label'));
label.textContent = labelText;
container.appendChild(label);
const input = createElement("input", inputId, { type: "number", id: inputId, placeholder: "0" });
label.appendChild(input);
if (copyId) {
const copyBtn = createElement("button", copyId, { type: "button", id: copyId, title: copyTitle });
copyBtn.innerHTML = copyIcon;
copyBtn.onclick = () => copyText(`${input.value}${labelText}`);
label.appendChild(copyBtn);
}
return input;
};
// Create inputs
const rootInput = createInputGroup("root", name.rootInput);
const pixelInput = createInputGroup("px", name.pixelInput, name.pixelCopy, "Copy Pixel");
const remInput = createInputGroup("rem", name.remInput, name.remCopy, "Copy Rem");
// Set initial values
const rootFontSize = window.getComputedStyle(document.documentElement).fontSize.replace('px', '');
rootInput.value = rootFontSize;
pixelInput.value = 10;
remInput.value = pixelInput.valueAsNumber / rootInput.valueAsNumber;
// Add event listeners
const updateValues = source => {
if (source === rootInput || source === pixelInput) {
remInput.value = pixelInput.valueAsNumber / rootInput.valueAsNumber;
} else if (source === remInput) {
pixelInput.value = remInput.valueAsNumber * rootInput.valueAsNumber;
}
};
for (const input of [rootInput, pixelInput, remInput]) {
input.addEventListener("input", event => updateValues(event.target));
}
document.addEventListener("keydown", event => {
if (event.key === "Escape") container.remove();
});
// Add styles
const colors = {
blue: '#b9e7de',
white: '#ffffff',
grayLight: '#edece8',
grayMid: '#6b6b6b',
grayDark: '#333333',
black: '#161613'
};
const style = document.createElement("style");
style.textContent = `
.${name.wrapper} {
width: 100%; letter-spacing: 1px; background-color: ${colors.blue} !important;
padding: 10px 60px; color: ${colors.black} !important; margin: auto !important;
position: fixed !important; top: 0 !important; right: 0 !important; left: 0 !important;
z-index: 2147483647 !important; font-size: 18px !important; font-family: helvetica !important;
display: flex !important; justify-content: center !important; gap: 2rem !important;
}
.${name.close} {
position: absolute; left: 0 !important; top: 0 !important; background-color: ${colors.grayLight} !important;
color: ${colors.black} !important; z-index: 30 !important; padding: 8px !important;
font-size: 18px !important; height: 100% !important; cursor: pointer !important;
display: flex !important; justify-content: center !important; align-items: center !important;
border: 0 !important; font-weight: normal !important; border-right: 2px solid ${colors.black} !important;
}
.${name.close}:hover { background-color: ${colors.white} !important; }
.${name.wrapper} label {
padding: 0 0 0 8px !important; border-top: 2px solid ${colors.grayDark} !important;
border-left: 2px solid ${colors.grayDark} !important; border-bottom: 2px solid ${colors.grayDark} !important;
background-color: #eee !important; font-family: monospace !important; letter-spacing: 0.5px !important;
display: flex !important; align-items: center !important; margin: 0 !important; font-size: inherit !important;
}
.${name.wrapper} input[type='number'] {
padding: 3px 6px !important; border-top: 0 !important; border-bottom: 0;
border-right: 2px solid ${colors.grayDark} !important; margin: 0 0 0 8px !important;
font-size: inherit; height: auto !important; color: ${colors.black} !important;
background-color: ${colors.white} !important; border-radius: 0 !important; -moz-appearance: textfield;
}
.${name.wrapper} input + button {
height: 100% !important; border: 0 !important; padding: 0 !important; margin: 0 !important;
cursor: pointer; border-right: 2px solid ${colors.grayDark} !important;
background-color: ${colors.grayMid} !important; display: flex !important; align-items: center !important;
}
.${name.wrapper} input::-webkit-outer-spin-button, .${name.wrapper} input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
.${name.wrapper} input::placeholder {
font-weight: bold !important; color: inherit !important;
}
`;
container.appendChild(style);
pixelInput.focus();
console.log(`${bookmarklet.name}: ${bookmarklet.version}`);
} catch (error) {
console.log(`${bookmarklet.name} : ${bookmarklet.version} : ${error}`);
}
// Paste the one line below into your bookmark url field for this code to work
javascript:(function(){const bookmarklet={name:"bookmakrlet__pixel-to-rem",version:"1.5"};try{const t={wrapper:`${bookmarklet.name}__wrapper`,close:`${bookmarklet.name}__close`,rootLabel:`${bookmarklet.name}__root-label`,rootInput:`${bookmarklet.name}__root-input`,pixelLabel:`${bookmarklet.name}__pixel-label`,pixelInput:`${bookmarklet.name}__pixel-input`,pixelCopy:`${bookmarklet.name}}__pixel-copy`,remLabel:`${bookmarklet.name}__rem-label`,remInput:`${bookmarklet.name}__rem-input`,remCopy:`${bookmarklet.name}__rem-copy`},e=(t,e,o={})=>{const n=document.createElement(t);return n.className=e,Object.entries(o).forEach((([t,e])=>n.setAttribute(t,e))),n},o=t=>{try{navigator.clipboard.writeText(t)}catch(t){console.error("Failed to copy:",t)}},n=e("div",t.wrapper);document.body.appendChild(n);const r=e("button",t.close,{type:"button"});r.textContent="Close",r.onclick=()=>n.remove(),n.appendChild(r);const a='<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z"/></svg>',i=(t,r,i,p)=>{const m=e("label",r.replace("input","label"));m.textContent=t,n.appendChild(m);const l=e("input",r,{type:"number",id:r,placeholder:"0"});if(m.appendChild(l),i){const n=e("button",i,{type:"button",id:i,title:p});n.innerHTML=a,n.onclick=()=>o(`${l.value}${t}`),m.appendChild(n)}return l},p=i("root",t.rootInput),m=i("px",t.pixelInput,t.pixelCopy,"Copy Pixel"),l=i("rem",t.remInput,t.remCopy,"Copy Rem"),c=window.getComputedStyle(document.documentElement).fontSize.replace("px","");p.value=c,m.value=10,l.value=m.valueAsNumber/p.valueAsNumber;const d=t=>{t===p||t===m?l.value=m.valueAsNumber/p.valueAsNumber:t===l&&(m.value=l.valueAsNumber*p.valueAsNumber)};for(const t of[p,m,l])t.addEventListener("input",(t=>d(t.target)));document.addEventListener("keydown",(t=>{"Escape"===t.key&&n.remove()}));const b={blue:"#b9e7de",white:"#ffffff",grayLight:"#edece8",grayMid:"#6b6b6b",grayDark:"#333333",black:"#161613"},s=document.createElement("style");s.textContent=`\n .${t.wrapper} {\n width: 100%; letter-spacing: 1px; background-color: ${b.blue} !important;\n padding: 10px 60px; color: ${b.black} !important; margin: auto !important;\n position: fixed !important; top: 0 !important; right: 0 !important; left: 0 !important;\n z-index: 2147483647 !important; font-size: 18px !important; font-family: helvetica !important;\n display: flex !important; justify-content: center !important; gap: 2rem !important;\n }\n .${t.close} {\n position: absolute; left: 0 !important; top: 0 !important; background-color: ${b.grayLight} !important;\n color: ${b.black} !important; z-index: 30 !important; padding: 8px !important;\n font-size: 18px !important; height: 100% !important; cursor: pointer !important;\n display: flex !important; justify-content: center !important; align-items: center !important;\n border: 0 !important; font-weight: normal !important; border-right: 2px solid ${b.black} !important;\n }\n .${t.close}:hover { background-color: ${b.white} !important; }\n .${t.wrapper} label {\n padding: 0 0 0 8px !important; border-top: 2px solid ${b.grayDark} !important;\n border-left: 2px solid ${b.grayDark} !important; border-bottom: 2px solid ${b.grayDark} !important;\n background-color: #eee !important; font-family: monospace !important; letter-spacing: 0.5px !important;\n display: flex !important; align-items: center !important; margin: 0 !important; font-size: inherit !important;\n }\n .${t.wrapper} input[type='number'] {\n padding: 3px 6px !important; border-top: 0 !important; border-bottom: 0;\n border-right: 2px solid ${b.grayDark} !important; margin: 0 0 0 8px !important;\n font-size: inherit; height: auto !important; color: ${b.black} !important;\n background-color: ${b.white} !important; border-radius: 0 !important; -moz-appearance: textfield;\n }\n .${t.wrapper} input + button {\n height: 100% !important; border: 0 !important; padding: 0 !important; margin: 0 !important;\n cursor: pointer; border-right: 2px solid ${b.grayDark} !important;\n background-color: ${b.grayMid} !important; display: flex !important; align-items: center !important;\n }\n .${t.wrapper} input::-webkit-outer-spin-button, .${t.wrapper} input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n }\n .${t.wrapper} input::placeholder {\n font-weight: bold !important; color: inherit !important;\n }\n `,n.appendChild(s),m.focus(),console.log(`${bookmarklet.name}: ${bookmarklet.version}`)}catch(t){console.log(`${bookmarklet.name} : ${bookmarklet.version} : ${t}`)}}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment