<!DOCTYPE html> <html> <head> <title>Testing Widows and Orphans</title> <style> body.hide-containers .container { display: none; } .container { width: 600px; height: 200px; -webkit-columns: 3; columns: 3; column-fill: auto; line-height: 20px; /* 10 lines per page */ font-size: 16px; margin: 0 0 20px 0; padding: 0; overflow: hidden; } .block { margin: 0 0 15px 0; padding: 0; } .top { color: red; } .bottom { color: green; } </style> <script> var results; function createTestContainer(id, description, blocks) { var label = document.createElement("h3"); label.textContent = id + " - " + description; document.body.appendChild(label); var element = document.createElement("div"); element.className = "container"; element.id = id; for (var i = 1; i <= blocks.length; i++) { var block = document.createElement("div"); block.className = "block"; var numLines = blocks[i-1]; for (var j = 1; j <= numLines; j++) { var line = document.createElement("span"); line.id = id + "-block-" + i + "-line-" + j; line.textContent = "Block " + i + " Line " + j; block.appendChild(line); block.appendChild(document.createElement("br")); } element.appendChild(block); } document.body.appendChild(element); return element; } function markTopLine(containerId, blockNumber, lineNumber) { var element = document.getElementById(containerId + "-block-" + blockNumber + "-line-" + lineNumber); element.className = "top"; } function markBottomLine(containerId, blockNumber, lineNumber) { var element = document.getElementById(containerId + "-block-" + blockNumber + "-line-" + lineNumber); element.className = "bottom"; } function logPass(msg) { log("PASS: " + msg); } function logFail(msg) { log("FAIL: " + msg); } function log(msg) { if (!results) results = document.createElement("div"); var output = document.createElement("p"); output.textContent = msg; results.appendChild(output); } function testIsFirstInColumn(containerId, blockNumber, lineNumber) { // Get the upper bounds of the container and line. var topOfContainer = document.getElementById(containerId).getBoundingClientRect().top; var topOfLine = document.getElementById(containerId + "-block-" + blockNumber + "-line-" + lineNumber).getBoundingClientRect().top; if (Math.abs(topOfContainer - topOfLine) < 5) // Give 5 pixels to account for subpixel layout. logPass(containerId + " Block " + blockNumber + " Line " + lineNumber + " is correct."); else logFail(containerId + " Block " + blockNumber + " Line " + lineNumber + " wasn't at the top of the column."); } function runTest() { var container; createTestContainer("test1", "Normal breaking", [5, 6, 5, 5]); markTopLine("test1", 1, 1); markBottomLine("test1", 2, 4); markTopLine("test1", 2, 5); markBottomLine("test1", 4, 1); markTopLine("test1", 4, 2); testIsFirstInColumn("test1", 1, 1); testIsFirstInColumn("test1", 2, 5); testIsFirstInColumn("test1", 4, 2); container = createTestContainer("test2", "Basic Orphan", [8, 6]); container.style.orphans = 2; markTopLine("test2", 1, 1); markBottomLine("test2", 1, 8); // Orphan break happens here. markTopLine("test2", 2, 1); testIsFirstInColumn("test2", 1, 1); testIsFirstInColumn("test2", 2, 1); container = createTestContainer("test3", "Basic Widow", [4, 6, 3]); container.style.widows = 2; markTopLine("test3", 1, 1); markBottomLine("test3", 2, 4); // Widow break happens here. markTopLine("test3", 2, 5); testIsFirstInColumn("test3", 1, 1); testIsFirstInColumn("test3", 2, 5); container = createTestContainer("test4", "Orphans causing Widows", [8, 6, 4, 4]); container.style.orphans = 2; container.style.widows = 2; markTopLine("test4", 1, 1); markBottomLine("test4", 1, 8); // Orphan break happens here. markTopLine("test4", 2, 1); markBottomLine("test4", 3, 2); // And that creates a widow forcing a break here. markTopLine("test4", 3, 3); testIsFirstInColumn("test4", 1, 1); testIsFirstInColumn("test4", 2, 1); testIsFirstInColumn("test4", 3, 3); container = createTestContainer("test5", "Widows blocked by Orphan rule", [7, 3, 4]); container.style.orphans = 2; container.style.widows = 2; markTopLine("test5", 1, 1); markBottomLine("test5", 2, 2); // This line should not move - protected by orphaning. markTopLine("test5", 2, 3); // This line won't be un-widowed - blocked by orphaning. testIsFirstInColumn("test5", 1, 1); testIsFirstInColumn("test5", 2, 3); container = createTestContainer("test6", "Ridiculous values", [7, 7, 7, 7]); container.style.orphans = 100; container.style.widows = 100; markTopLine("test6", 1, 1); markBottomLine("test6", 1, 7); // Orphan break happens here. markTopLine("test6", 2, 1); // Adopted. markBottomLine("test6", 2, 7); // Orphan break. markTopLine("test6", 3, 1); // Adopted. testIsFirstInColumn("test6", 1, 1); testIsFirstInColumn("test6", 2, 1); testIsFirstInColumn("test6", 3, 1); if (results) document.body.appendChild(results); if (window.testRunner) { // Hide all the containers and leave just the test results for text output. document.body.className = "hide-containers"; testRunner.notifyDone(); } } if (window.testRunner) { testRunner.dumpAsText(); testRunner.waitUntilDone(); } window.addEventListener("load", runTest, false); </script> </head> <body> <p> Testing widows and orphans. Any green lines should be at the bottom of pages/columns, and any red lines should be at the top of pages/columns. </p> </body> </html>