Get started
Migrate a project to LUZ
Move a project that has its own CSS to LUZ one page at a time, in five steps. An AI does the mechanical work; you decide and check.
How the migration works
Keep the old CSS running until the last page has moved. One rule comes before all the others: an AI speeds up the mechanical work, and you decide and check.
It fits a site of many pages or of content. In a single-page app built on a component library such as React or Vue, a migration changes the look but not the components: see what it costs.
What makes it possible is luz.conditional.css, the same file as luz.css with the reset and the bare elements limited to a region marked data-luz. Install it in step 3.
Before you touch anything
- Make an inventory. Ask the AI to list the pages or templates, the components of the old framework and how often each is used, the JavaScript that depends on classes or markup (modals, menus, tabs, validation) and every
!important. Correct the list: it is the map of the migration. - Take screenshots. One of each page in the states that matter: light and dark, phone and desktop, a form with an error, an open modal. Without them you cannot tell what you broke.
- Write smoke tests. If the project has no tests, ask the AI for a few on what must not break: the form sends, the menu opens, the login works. You run them.
- Write down when a page is done, once. The page loads no class or script of the old framework,
luz-checkand an accessibility check come out clean, the screenshots match except what you chose to change, and the smoke tests pass.
The five steps
Step 1: tokens with your current brand
Make a look of your own from themes/_template.css with the values you use today. The AI maps your variables or loose colors to the tokens of LUZ and gives you the table; you check it. Nothing changes on screen, and your CSS and LUZ now share a vocabulary. Make it yours shows how.
Step 2: the old CSS in a layer before LUZ
Put the old stylesheet in a layer that comes before luz, so LUZ wins where both style an element:
/* site.css, linked before the LUZ stylesheets */
@layer legacy, luz;
@import url("legacy.css") layer(legacy);
- Check the
!importantrules. In an earlier layer they still win over LUZ. The AI lists them; you decide which go now. - Look for CSS with no layer. A style attribute or the CSS of a plugin beats every layer, LUZ included. The screenshots show it.
- Use
@importfor the migration only. It adds a request. Cascade layers explains the order.
Step 3: the first region
Load luz.conditional.css instead of luz.css, pick a small page with no JavaScript, and put data-luz on the element that holds it. Inside, the HTML with no classes comes out styled by LUZ:
<main data-luz>
<h1>Contact us</h1>
<form action="/contact" method="post">
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<button>Send</button>
</form>
</main>
Do this one by hand. What you learn goes into the prompt for the next pages.
Step 4: page by page
Choose the order, from the simple pages to the complex ones, with the pages that share a template together. Migrate the shared parts (header, footer, menu) once, after the simple pages and before the complex ones, so you do not keep two headers for months. For each page, repeat the same loop:
- The AI, with the LUZ prompt, puts the page in the region, removes the classes of the old framework, leaves the HTML semantic, and adds a LUZ class only where HTML is not enough. Removing is safer than adding.
- It runs
npx @luz-ds/check@0.3.0and an accessibility check, and shows you what changed and what is left, never the whole file rewritten. - You read the diff and the screenshots, and run the smoke tests.
- One commit per page, so you can revert a page and not a month.
luz-check reads LUZ’s classes, elements, load order and color tokens. It does not look for classes of the old framework that are left over: search for them yourself.
Step 5: remove the old CSS
When no page uses the old CSS, remove the legacy layer, load luz.css instead of luz.conditional.css, and drop data-luz. The AI searches for the classes and scripts that are left; you delete the old framework. Never earlier: the AI deletes nothing without your OK for this step.
Where the bugs come from
The bugs of a migration do not come from the new CSS. They come from deleting the old code without knowing who used it.
- The JavaScript of the old framework. A Bootstrap modal is a
dialogin LUZ, but the code that opened or validated it is still there. The AI tells you which script each page touches; you review the replacement, because it holds business logic. - Forms. Migrate one form first, from the field to the submit.
- Shared parts. Migrate the header, footer and menu once, as step 4 says.
- JavaScript that looks for old classes. Before you delete a class, search the scripts and templates for it. A
querySelector('.btn-primary')that stops finding its button gives no error: it just stops working.
Who does what
The AI works on the mechanical parts; you keep every decision.
| The AI | You |
|---|---|
Makes the inventory, maps variables to tokens, lists the !important rules | Reads and corrects the inventory, and chooses the order of the pages |
Writes the smoke tests and the tests of each page | Runs them and decides if they are enough |
Removes classes, leaves semantic HTML, adds the few LUZ classes | Does the first region by hand and reviews every diff |
Runs luz-check and the accessibility check, and sums up what changed and what is left | Looks at the screenshots and approves the commit |
Searches for classes and scripts left over before anything is deleted | Replaces the JavaScript that holds business logic, and deletes the old framework |
What it costs, and when not to
A migration has three costs, and one case where it does not pay.
- The costs: two visual languages for a while (step 1 softens it), the weight of both stylesheets while it lasts, and the JavaScript of the old framework, which you must rewrite.
- When not to: in a single-page app built on a component library for React or Vue, you change the look but not the components. It is more honest to rewrite screen by screen with LUZ.
Next steps
- Load luz.conditional.css for a project that already has a design.
- Work with AI: the prompts, and the checker that reviews what the AI writes.
- Change the default styles that LUZ gives the bare elements.