Percent by volume
HTML for this example
Select the code and use your copy shortcut. Changes in this preview are temporary.
<!doctype html>
<html lang="en-US"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Percent by volume</title><style>*{box-sizing:border-box}body{margin:0;background:#f3f4f2;color:#202c32;font:16px/1.5 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}main{max-width:1120px;margin:auto;padding:30px 28px 60px}header{margin-bottom:22px}.eyebrow{font-size:12px;letter-spacing:.14em;text-transform:uppercase;font-weight:750;color:#59676b}h1{font-size:clamp(25px,4vw,36px);line-height:1.15;letter-spacing:-.035em;margin:7px 0 10px}h2{font-size:21px;line-height:1.3;margin:0 0 16px}h3{font-size:17px;margin:0 0 10px}p{margin:8px 0 16px}label{display:block;font-size:14px;font-weight:650;margin:12px 0 5px}input,select,textarea,button{font:inherit}input,select,textarea{width:100%;min-width:0;border:1px solid #b6c0bf;border-radius:7px;background:#fff;color:#202c32;padding:10px 12px}textarea{resize:vertical;min-height:88px}input[type=checkbox]{width:18px;height:18px;vertical-align:middle;margin-right:8px}button{border:1px solid #b8c3c1;border-radius:7px;padding:10px 15px;background:#fff;color:#203632;font-weight:650;cursor:pointer}button.primary{background:#243f3c;color:white;border-color:#243f3c}button:hover{filter:brightness(.95)}button:disabled{opacity:.48;cursor:not-allowed}:focus-visible{outline:3px solid #b05814;outline-offset:3px}.buttons{display:flex;gap:8px;flex-wrap:wrap;margin-top:18px}.panel{background:#fff;border:1px solid #d7ddda;border-radius:12px;padding:24px}.split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:22px}.row{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.result{background:#e4eee8;border:1px solid #c5d6ca;border-radius:12px;padding:28px}.big{font-size:clamp(32px,5vw,56px);font-weight:740;line-height:1.14;letter-spacing:-.04em;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.muted{color:#59686a;font-size:14px}.tag{display:inline-block;background:#edf0ed;border-radius:4px;padding:3px 8px;font-size:12px;font-weight:700}.error{color:#9d301b;font-weight:650;min-height:24px;margin-top:10px}.note{border-left:3px solid #9a794a;padding:10px 15px;background:#faf5e9;margin:18px 0}.below{margin-top:28px}.record{white-space:pre-wrap;overflow-wrap:anywhere;font:14px/1.65 ui-monospace,SFMono-Regular,Consolas,monospace;background:#f2f4f1;padding:18px;border-radius:8px}table{width:100%;border-collapse:collapse;font-size:14px}th,td{text-align:left;vertical-align:top;border-bottom:1px solid #dce1dd;padding:12px 10px;overflow-wrap:anywhere}th{color:#59686a;font-size:12px}a{color:#2c5a6a;overflow-wrap:anywhere}details{margin-top:20px}summary{cursor:pointer;font-weight:650}hr{border:0;border-top:1px solid #d6dcd6;margin:22px 0}[hidden]{display:none!important}ol,ul{padding-left:23px}.statline{display:flex;gap:20px;flex-wrap:wrap;margin:18px 0}.statline strong{display:block;font-size:24px}.inline{display:flex;align-items:center;gap:8px}.inline label{margin:0} .blank{min-height:36px;border-bottom:1px dashed #aebbb5;color:#66736d;font-size:13px;padding:8px 0}@media(max-width:720px){main{padding:22px 18px 45px}.split{grid-template-columns:1fr}.panel,.result{padding:20px}.row{gap:12px}th,td{padding:10px 6px}}@media(max-width:400px){main{padding:18px 14px 40px}.big{font-size:34px}button{padding:10px 12px}.row{grid-template-columns:1fr}.panel,.result{padding:17px}}.strip{display:flex;gap:18px;justify-content:space-between;align-items:center;flex-wrap:wrap}.inline{flex-wrap:wrap}.metric{font-size:clamp(28px,4vw,43px);font-weight:750;line-height:1.2;letter-spacing:-.025em;font-variant-numeric:tabular-nums}.three{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}.caption{font-size:13px;color:#59686a}.gameBoard{display:grid;gap:2px;background:#bbc9c3;border:8px solid #213e3a;border-radius:8px;overflow:hidden}.cell{aspect-ratio:1;background:#f2f6ee;text-align:center;display:grid;place-items:center;font-size:clamp(10px,2vw,17px);line-height:1}.cell.head{background:#233f39;color:white}.cell.body{background:#608c71;color:#fff}.cell.food{background:#f0c17b;color:#54370d}.cell.active{background:#e6b677;color:#342510}.cell.fixed{background:#53798a;color:white}.gameArea{max-width:700px;margin:auto}.scorebar{display:flex;gap:22px;flex-wrap:wrap;margin-bottom:15px}.scorebar strong{font-size:26px;display:block}.gameControls{display:grid;gap:8px;align-content:start}.gameControls button{padding:9px 8px}.boardSplit{display:grid;grid-template-columns:minmax(0,1fr) 130px;gap:18px;align-items:start}.state{font-weight:700;min-height:26px}button[aria-pressed=true]{background:#243f3c;color:white}.gameArena:focus-visible{outline-offset:8px}svg{max-width:100%;height:auto}.paper{aspect-ratio:3/4;width:min(100%,250px);margin:auto;background:#fff;border:1px solid #b6bfb8;box-shadow:0 5px 18px #20352e12}.paperCaption{text-align:center;font-size:13px}.sectionline{border-top:1px solid #c8d2cb;padding-top:18px}.warn{background:#fbecd2;color:#76521e;padding:12px 15px;border-radius:6px}.docGrid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:24px}.readout{font-family:ui-monospace,monospace}.sourceLinks{font-size:13px;margin-top:18px}.sourceLinks a{margin-right:12px}.answerLine{font-size:21px;font-weight:700}.keypad{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:7px}.keypad button{min-height:43px;padding:8px 5px}textarea{overflow-wrap:anywhere}@media(max-width:720px){.docGrid{grid-template-columns:1fr}.three{grid-template-columns:1fr}.gameArea{max-width:540px}.boardSplit{gap:12px;grid-template-columns:minmax(0,1fr) 112px}}@media(max-width:400px){.boardSplit{grid-template-columns:minmax(0,1fr) 96px;gap:9px}.gameControls button{font-size:13px}.gameBoard{border-width:5px;gap:1px}.keypad{gap:5px}.scorebar{gap:16px}.scorebar strong{font-size:22px}}</style></head><body><main><header><div class="eyebrow">Fictional pure component A / Measured final solution</div><h1>Percent by volume</h1></header>
<section class="result" aria-live="polite"><span class="eyebrow" id="answerLabel">Component / final solution × 100</span><div id="answer" class="big">12.5% v/v</div><div id="formula" class="answerLine">25 mL ÷ 200 mL × 100 = 12.5%</div><p class="caption">Use the measured final solution volume as the denominator.</p></section>
<form id="form" class="panel below" novalidate><label for="mode">Solve for</label><select id="mode"><option value="forward">Percent by volume</option><option value="target">Component volume for a target percentage</option></select><div class="row"><div><label for="amount" id="amountLabel">Component volume</label><input id="amount" value="25" inputmode="decimal"><label for="unit" id="unitLabel">Component unit</label><select id="unit"><option>mL</option><option>L</option></select></div><div><label for="final">FINAL solution volume</label><input id="final" value="200" inputmode="decimal"><label for="finalUnit">Final solution unit</label><select id="finalUnit"><option>mL</option><option>L</option></select></div></div><div id="outputRow" hidden><label for="outputUnit">Component result unit</label><select id="outputUnit"><option>mL</option><option>L</option></select></div><div class="buttons"><button class="primary">Calculate</button><button id="reset" type="button">Reset to empty</button><button id="example" type="button">Load 25 / 200 example</button></div><p id="feedback" class="error" role="status"></p></form>
<section class="panel below"><h2>Calculation record</h2><div id="record" class="record"></div><p>0 component volume is valid with a positive final volume. Component volume must not exceed final solution volume; target percentage must be 0–100.</p><p class="muted">Only mL and L are normalized (1 L = 1,000 mL). Entries require a leading digit and at most six decimals; each entered volume is limited to 1,000,000 units. No exponent, comma, mass, density or stock-concentration conversion is supported. 175 mL of solvent is not the denominator, and adding component and solvent volumes does not establish the measured final volume. This fictional exercise supplies no real preparation instructions.</p><a href="https://chem-textbook.ucalgary.ca/version2/review-of-background-topics/measurements-and-data/measurements-in-chemistry/volume-percent-v-v/">Volume percent and final-volume reference</a></section><footer class="below muted">Local working example. Edits last only while this page is open.</footer></main><script data-app>
(()=>{
const $=id=>document.getElementById(id),text=(id,v)=>$(id).textContent=String(v),on=(id,e,f)=>$(id).addEventListener(e,f);const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));function download(name,content,type='text/plain'){const u=URL.createObjectURL(new Blob([content],{type})),a=document.createElement('a');a.href=u;a.download=name;document.body.append(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(u),1000)};
function parse(s,max=1000000){s=String(s).trim();if(!/^[0-9]+(?:[.][0-9]{1,6})?$/.test(s)||!Number.isFinite(+s)||+s>max)throw Error('Enter a nonnegative number up to '+max+' with a leading digit and at most six decimals. Blank is missing.');return +s}function factor(u){if(u==='mL')return 1;if(u==='L')return 1000;throw Error('Unsupported unit.')}function calculate(mode,a,unit,final,finalUnit,outputUnit='mL'){if(!['forward','target'].includes(mode))throw Error('Unsupported mode.');const f=parse(final)*factor(finalUnit);if(f<=0)throw Error('Final solution volume must be greater than zero.');if(mode==='forward'){const c=parse(a)*factor(unit);if(c>f)throw Error('Component volume cannot exceed final solution volume.');return {value:c/f*100,componentML:c,finalML:f,unit:'% v/v'}}const p=parse(a,100),c=p/100*f;return {value:c/factor(outputUnit),componentML:c,finalML:f,percent:p,unit:outputUnit}}function fmt(n){if(n>0&&n<0.000001)return '<0.000001';return Number(n.toFixed(6)).toString()}
function clear(){text('answer','Calculate to see result');text('formula','');text('record','Inputs changed; no current calculation.');text('feedback','')}function mode(){const target=$('mode').value==='target';text('amountLabel',target?'Target percentage (enter 12.5 for 12.5%)':'Component volume');$('unit').hidden=target;$('unitLabel').hidden=target;$('outputRow').hidden=!target;text('answerLabel',target?'Target percentage / 100 × final volume':'Component / final solution × 100');clear()}
function update(){clear();try{const m=$('mode').value,r=calculate(m,$('amount').value,$('unit').value,$('final').value,$('finalUnit').value,$('outputUnit').value);text('answer',(r.value>=0.000001&&Number(r.value.toFixed(6))!==r.value?'≈':'')+fmt(r.value)+' '+r.unit);text('formula',m==='forward'?fmt(r.componentML)+' mL ÷ '+fmt(r.finalML)+' mL × 100 = '+fmt(r.value)+'%':fmt(r.percent)+' / 100 × '+fmt(r.finalML)+' mL = '+fmt(r.value)+' '+r.unit);text('record','Raw entry: '+$('amount').value+(m==='forward'?' '+$('unit').value:'%')+'; final '+$('final').value+' '+$('finalUnit').value+'\nNormalized component: '+r.componentML+' mL\nNormalized final: '+r.finalML+' mL\nInternal result: '+r.value+' '+r.unit+'\nDisplay: up to six decimals; values are approximate when rounded.');text('feedback','Calculated from the stated component and final solution volumes.')}catch(e){text('feedback',e.message)}}
on('form','submit',e=>{e.preventDefault();update()});on('mode','change',()=>{$('amount').value='';$('final').value='';mode()});['amount','final','unit','finalUnit','outputUnit'].forEach(id=>on(id,'input',clear));function reset(){['amount','final'].forEach(id=>$(id).value='');$('mode').value='forward';['unit','finalUnit','outputUnit'].forEach(id=>$(id).value='mL');mode()}on('reset','click',reset);on('example','click',()=>{reset();$('amount').value='25';$('final').value='200';update()});window.app={parse,factor,calculate,fmt};update();
})();
</script>
<script>
// Local calculation controls: no native form submission or sandbox permissions required.
(()=>{const form=document.getElementById('form');if(!form)throw Error('Calculation form missing');const dispatch=()=>form.dispatchEvent(new Event('submit',{bubbles:true,cancelable:true}));const buttons=[...form.querySelectorAll('button')].filter(button=>button.type==='submit');if(buttons.length!==1)throw Error('Expected one calculation control');for(const button of buttons){button.type='button';button.addEventListener('click',dispatch);}form.addEventListener('keydown',event=>{if(event.key==='Enter'&&!event.isComposing&&['INPUT','SELECT'].includes(event.target.tagName)){event.preventDefault();dispatch();}});})();
</script>
</body></html>