Curtains and roman blinds and fabric calculator

Made to Measure Calculators

:root {
–ink: #252126;
–muted: #6b6269;
–line: #ded6dd;
–soft: #f8f5f7;
–accent: #77566d;
–accent-dark: #55384e;
–white: #fff;
}
body {
margin: 0;
padding: 24px;
color: var(–ink);
background: #f2f0f2;
font-family: Arial, Helvetica, sans-serif;
}
.mtm-calcs {
max-width: 1040px;
margin: 0 auto;
background: var(–white);
border: 1px solid var(–line);
border-radius: 8px;
overflow: hidden;
}
.curtain-hero {
min-height: 180px;
background: #f6f0f3;
border-bottom: 1px solid var(–line);
}
.curtain-hero svg {
display: block;
width: 100%;
height: auto;
}
.tabs {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
border-bottom: 1px solid var(–line);
background: var(–soft);
}
.tabs button {
min-height: 52px;
padding: 10px;
border: 0;
border-right: 1px solid var(–line);
color: var(–ink);
background: transparent;
font-weight: 700;
cursor: pointer;
}
.tabs button:last-child { border-right: 0; }
.tabs button.active {
color: #fff;
background: var(–accent);
}
.panel {
display: none;
padding: 24px;
}
.panel.active { display: block; }
h2 {
margin: 0 0 18px;
font-size: 24px;
line-height: 1.25;
}
.grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
.field {
display: grid;
gap: 6px;
}
.field label {
font-size: 14px;
font-weight: 700;
}
input, select {
min-height: 44px;
width: 100%;
box-sizing: border-box;
padding: 10px 12px;
border: 1px solid var(–line);
border-radius: 6px;
background: #fff;
color: var(–ink);
font-size: 16px;
}
.result {
margin-top: 20px;
padding: 18px;
display: grid;
gap: 8px;
background: var(–soft);
border-radius: 8px;
}
.price {
color: var(–accent-dark);
font-size: 30px;
font-weight: 800;
}
.note {
margin: 0;
color: var(–muted);
font-size: 13px;
line-height: 1.45;
}
.quote {
display: inline-flex;
align-items: center;
justify-content: center;
margin-top: 14px;
min-height: 42px;
padding: 0 16px;
border-radius: 6px;
color: #fff;
background: var(–accent);
text-decoration: none;
font-weight: 700;
}
@media (max-width: 760px) {
body { padding: 12px; }
.tabs { grid-template-columns: 1fr 1fr; }
.panel { padding: 18px; }
.grid { grid-template-columns: 1fr; }
}




Curtain Making Service

Fabric width (cm)
Pattern repeat (cm)
Width (cm)
Drop (cm)
Pair or singlePairSingle
Pole or trackPoleTrack
HeadingPencil pleatDouble pleatEyeletWave heading
LiningNo liningStandardExtra thick thermalLined and interlined
BlackoutNoYes

Total price

Request quote

Roman Blind Making Service

Fabric width (cm)
Pattern repeat (cm)
Width (cm)
Drop (cm)
Installation height (cm)
LiningNo liningStandardExtra thick thermalLined and interlined
BlackoutNoYes
Chain positionLeftRight

Total price

Request quote

Curtain Fabric Calculator

Fabric name
Fabric width (cm)
Pattern repeat (cm)
Price per metre
Pole or trackPoleTrack
Width (cm)
Total drop (cm)
Pair or singlePairSingle
HeadingPencil pleatDouble pleatEyeletWave heading
InterlinedNoYes

Fabric required

Email results

Blind Fabric Calculator

Blind typeRoman blindRoller blind
Fabric name
Fabric width (cm)
Pattern repeat (cm)
Price per metre
Width (cm)
Drop (cm)

Fabric required

Email results

(function () {
const money = (n) => “GBP ” + Math.max(0, n).toFixed(2);
const metres = (cm) => (Math.ceil(cm / 10) / 100).toFixed(2).replace(/\.00$/, “”) + ” m”;
const num = (panel, name) => Number(panel.querySelector(‘[data-field=”‘ + name + ‘”]’).value) || 0;
const val = (panel, name) => panel.querySelector(‘[data-field=”‘ + name + ‘”]’).value;
const fullness = { pencil: 2, double: 2.5, eyelet: 2, wave: 2.3 };
const emailAddress = “charmshape@gmail.com”;
const curtainWidthBands = [36, 105, 173, 242, 310, 379, 447, 516, 584, 653, 721, 790, 858, 927, 995, 1064, 1132, 1201];
const curtainBaseAt100 = [123, 185, 248, 310, 372, 435, 497, 559, 622, 684, 746, 809, 871, 933, 996, 1058, 1120, 1183];
const romanWidths = [50, 100, 150, 200, 250];
const romanDrops = [50, 100, 150, 200, 250, 300];
const romanStandard = [
[155, 180, 216, 252, 292, 333],
[178, 212, 259, 316, 370, 416],
[235, 276, 348, 419, 511, 601],
[267, 330, 420, 510, 590, 716],
[298, 369, 471, 627, 777, 804]
];

function repeatLength(length, repeat) {
return repeat > 0 ? Math.ceil(length / repeat) * repeat : length;
}

function curtainFabric(panel) {
const width = num(panel, “width”);
const drop = num(panel, “drop”);
const fabricWidth = Math.max(1, num(panel, “fabricWidth”));
const repeat = num(panel, “repeat”);
const pair = val(panel, “pair”) === “pair” ? 2 : 1;
const f = fullness[val(panel, “heading”)];
const widths = Math.max(pair, Math.ceil((width * f) / fabricWidth));
const cutDrop = repeatLength(drop + 25, repeat);
const requiredCm = widths * cutDrop;
const cost = requiredCm / 100 * num(panel, “ppm”);
panel.querySelector(‘[data-output=”required”]’).textContent = metres(requiredCm);
panel.querySelector(‘[data-output=”note”]’).textContent =
“Fabric cost ” + money(cost) + “. ” + widths + ” fabric width(s), cut drop ” + cutDrop + ” cm, fullness ” + f.toFixed(2) + “.”;
panel.querySelector(‘[data-output=”email”]’).href = makeMailto(“Curtain fabric result”, panel.querySelector(‘[data-output=”note”]’).textContent);
}

function blindFabric(panel) {
const width = num(panel, “width”);
const drop = num(panel, “drop”);
const fabricWidth = Math.max(1, num(panel, “fabricWidth”));
const repeat = num(panel, “repeat”);
const type = val(panel, “type”);
const allowance = type === “roman” ? 20 : 30;
const widths = Math.max(1, Math.ceil(width / fabricWidth));
const cutDrop = repeatLength(drop + allowance, repeat);
const requiredCm = widths * cutDrop;
const cost = requiredCm / 100 * num(panel, “ppm”);
panel.querySelector(‘[data-output=”required”]’).textContent = metres(requiredCm);
panel.querySelector(‘[data-output=”note”]’).textContent =
“Fabric cost ” + money(cost) + “. ” + widths + ” fabric width(s), cut drop ” + cutDrop + ” cm.”;
panel.querySelector(‘[data-output=”email”]’).href = makeMailto(“Blind fabric result”, panel.querySelector(‘[data-output=”note”]’).textContent);
}

function lookupIndex(maxes, value) {
const idx = maxes.findIndex((max) => value x y {
button.addEventListener(“click”, () => {
document.querySelectorAll(“.tabs button”).forEach((b) => b.classList.remove(“active”));
document.querySelectorAll(“.panel”).forEach((panel) => panel.classList.remove(“active”));
button.classList.add(“active”);
document.getElementById(button.dataset.tab).classList.add(“active”);
});
});

Object.keys(calculators).forEach((id) => {
const panel = document.getElementById(id);
panel.querySelectorAll(“input, select”).forEach((field) => {
field.addEventListener(“input”, () => calculators[id](panel));
field.addEventListener(“change”, () => calculators[id](panel));
});
calculators[id](panel);
});
})();