I’ve been experimenting with what a Canva-like editing experience might look like in WordPress. The hard part is not the dragging. It is turning what you dragged into a real WordPress page.
Drag a heading anywhere on the page and you get two things that are not supposed to go together. The freedom of a design tool, and an ordinary WordPress page at the end of it.
Free placement normally means absolutely positioned boxes. They fall over the moment the text grows, or someone opens the page on a phone. Which is why nearly every builder goes the other way and asks you to pick rows and columns first.
There is a third way. You put things where you want, and the editor reads the grid back out of what you did.
It is not a canvas
Worth clearing up first, because the word does confuse things. Here, canvas just means the page you drag on, the way a designer says canvas. Nothing is being painted into an HTML <canvas> tag.
Every piece on the page is real HTML the whole time you are working on it. A heading is an h2 you can select and type into. All the editor keeps about it is four numbers: how far across, how far down, how wide, how tall. The page is always 1200 units wide, so those numbers mean the same thing on any screen.
1. What you drag
A real heading, a real picture, a real button. You can select the words and type into them. Drag one anywhere you like.
On screen: an <h2> you can select.
2. What gets remembered
Four numbers for each piece: how far across, how far down, how wide, how tall — on a page a fixed 1200 units wide.
In the model: {x:72, y:118, w:470, h:200}
3. What gets published
Ordinary WordPress blocks, plus a stylesheet that turns those numbers into a real CSS grid. The browser lays it out natively.
<style>
.sec-4 {
display: grid;
grid-template-columns: 6cqw 39cqw …
}
.el-2 { grid-area: 2 / 2 / 3 / 3 }
</style>
<!-- wp:heading -->
<h2 class=“el-2”>Buildings that
keep their quiet</h2>
In the page: the same <h2>, in a grid cell.
The same heading at three moments: on screen, in the model, and in the saved page.
That middle step is the bit that makes everything else possible. A page is a table of numbers, and numbers can be measured, compared and solved. A picture cannot.
Where the grid comes from
Here is the part people expect to be complicated. It is not.
Take every piece and note its left and right edge. Draw a line at each one. Do the same downwards with the tops and bottoms. Three pieces will usually give you five lines across and four down.
The gaps between those lines are your columns and rows. Nobody picked them. They are just what your edges left behind. Then each piece takes the cells it covers, from the line its left edge landed on to the line its right edge landed on. Those four numbers go straight into grid-area.
1. Three pieces, dragged
Each one knows where it starts and ends: a left and a right edge, a top and a bottom.
Heading: across 24→142
2. Every edge becomes a line
Collect all the left and right edges and draw a line at each. Same downwards with tops and bottoms. Edges within a hair of each other count as one line.
Five lines across, four down.
3. The gaps are the grid
The space between one line and the next is a column, or a row. That is the whole grid — nothing is chosen, it is just what your edges left behind.
Four columns, three rows.
4. Each piece takes its cells
A piece sits from the line its left edge landed on to the line its right edge landed on. Those four numbers are what gets written down.
The photo: grid-area: 1 / 3 / 4 / 5
Four steps from three dragged boxes to a real CSS grid.
The one clever bit
Edges within a hair of each other get treated as the same line.
Drag a heading to within a few pixels of the paragraph underneath and the editor counts both edges as one, so they line up exactly. That does two jobs. Things click into place without you fiddling, and the grid stays small. A handful of clean columns instead of forty ragged ones, because near misses get merged rather than each demanding a column of its own.
A normal builder asks you to pick a layout, then pour things into it. This one lets you put things where you want, then reads the layout back out.
Why bother
Because of what survives.
The words are real words, so a screen reader can read them and Google can find them. The layout is a real grid, so a phone can restack it into one column without anyone drawing a second version. The page opens in the WordPress editor, because it is made of WordPress blocks. And the stylesheet is baked in next to those blocks, so if you turn the plugin off the page is still there and still looks right.
That last one matters more than it sounds. Most builders own the rendering. Turn one off and you are left with a page full of shortcodes and a bad afternoon.
The hard part
The hard part is not the idea. It is everything round it.
Text changes height as you type, so the grid has to be worked out again while you are working. Two bits of text must never end up sitting on top of each other. Words on a photo need their contrast checked. A phone needs a sensible order to stack things in.
How the drag-and-drop actually works
You design freeform (drag anything anywhere), but what gets saved is a clean, responsive CSS grid.
Here’s the sequence:
1. While you’re dragging
The element temporarily gets inline absolute positioning:
<h2 style="position: absolute; left: 234px; top: 456px; width: 480px;">
Your heading
</h2>
A semi-transparent ghost follows your pointer, and a dashed outline shows where the element will land when you let go.
2. On drop
- The temporary inline styles are stripped.
- The final position is recorded in the model as design-unit coordinates on a 0–1200 scale.
- The grid solver runs.
3. The grid solver
This translates the freeform layout into a grid. It:
- Collects every x and y edge of every element.
- Clusters near-aligned edges together, within 8 units.
- Turns those clusters into grid lines.
- Converts the gaps between lines into grid tracks, using
cqwunits relative to the container width. - Maps each element to its nearest grid lines using
grid-area: row1/col1/row2/col2.
4. What actually renders
Clean semantic HTML with a scoped stylesheet:
<div class="layout-section layout-sec-1">
<style>
.layout-section.layout-sec-1 {
display: grid;
grid-template-columns: 6cqw 12cqw 40cqw 1fr 6cqw;
grid-template-rows:
minmax(8cqw, max-content)
minmax(12cqw, max-content);
}
.layout-section.layout-sec-1 .layout-el-1 {
grid-area: 1/2/2/4;
z-index: 2;
}
</style>
<h2 class="layout-el-1">Your heading</h2>
</div>
No absolute positioning survives. The published layout uses CSS grid, with dimensions that scale relative to its container. Because the saved output contains the HTML and styles, the design can remain intact when the plugin is deactivated.
The freeform canvas is the authoring experience; the grid is the output format.
Leave a Reply