Ein Template ist eine gewöhnliche statische Website (HTML + CSS + Bilder, kein JavaScript). ProntoSite übernimmt sie beim Import bytetreu und leitet alles aus Struktur, Wiederholung und Position ab. Es gibt keine ProntoSite-Spezialattribute, die du setzen musst oder darfst. Ein gutes Template ist eines, das ProntoSite ohne "nicht erkannt"-Meldungen versteht: Bereiche, Wiederholungsgruppen, Navigation, Formulare und Interaktionsmuster sind dann alle sauber bearbeitbar.
Diese Seite beschreibt, wie du dein HTML baust, damit das gelingt, und warum die jeweilige Regel fürs Ergebnis wichtig ist.
1. Semantische Struktur #
Regel: Gliedere Seiten mit den fünf Bereichs-Tags <header>, <nav>, <main>, <aside>, <footer> (plus <article>). Baue innerhalb von <main> jede Sektion als <section> mit eigener Überschrift (h1–h6), die Überschriften-Hierarchie absteigend.
Warum: ProntoSite kennt genau diese Bereiche und bildet daraus die Gliederung (Inhaltsverzeichnis und Breadcrumb): Kopfbereich, Navigation, Inhalt, Seitenleiste, Fußbereich. Überschriften eröffnen die Blöcke der Gliederung und geben jedem Container ein sprechendes Label (die erste Überschrift im Abschnitt; fehlt sie, greift das System auf Bild-Alt oder einen Kurztext zurück). Sektionen ohne erkennbare Rolle tauchen in der Prüfansicht als "Bereich ohne Rolle" auf.
Text-Elemente: Bearbeitbarer Text muss in einem echten Text-Element stehen: h1–h6, p, li, button, label, td, th, figcaption, blockquote, dt, dd, caption, summary, legend, span (auch ein div, das NUR Inline-Kinder enthält, zählt). Text, der direkt in einem Layout-div zwischen Block-Kindern liegt, wird NICHT editierbar.
<!-- RICHTIG: Bereichs-Tags, Sektion mit Überschrift, Text in <p> -->
<main>
<section class="leistungen">
<h2>Unsere Leistungen</h2>
<p>Wir begleiten Sie von der Planung bis zur Übergabe.</p>
</section>
</main>
<!-- FALSCH: div-Suppe ohne Überschrift, nackter Text im Layout-Container -->
<div class="wrapper">
<div class="box">
Wir begleiten Sie von der Planung bis zur Übergabe.
<div class="deco"></div>
</div>
</div>
2. Wiederholungsgruppen (Karten, Listen, Team-Grids) #
Regel: Baue gleichartige Einträge als direkte Geschwister mit demselben Tag und derselben Kind-Tag-Struktur — und liefere mindestens 3 Einträge.
Warum: ProntoSite gruppiert Geschwister, wenn ihr Tag gleich ist und ihre direkten Kind-Tags weitgehend übereinstimmen. Ab 3 Einträgen gilt eine Gruppe als sicher erkannt; bei nur 2 Einträgen bleibt sie unsicher (löst beim Duplizieren eine Rückfrage aus und erscheint in der Prüfansicht unter "nicht erkannt"). Nur auf sicheren Gruppen funktionieren Duplizieren, Entfernen und Umsortieren reibungslos.
Listen: <ul>/<ol> mit <li> bilden IMMER eine vollständige Gruppe — auch bei innerer Abweichung. Verwende für Aufzählungen also echte Listen.
Footer-Spalten: Ein Container im <footer>, dessen direkte Kinder überwiegend "spaltenartig" sind, wird als Spalten-Gruppe geführt. Spaltenartig heißt: div/section/nav/li mit eigener Überschrift. Gib jeder Footer-Spalte deshalb eine h4/h5-Überschrift.
<!-- RICHTIG: 3 Karten, identische Kind-Struktur (img+h3+p+a) -->
<div class="grid">
<article class="card"><img src="img/a.jpg" alt="…"><h3>Planung</h3><p>…</p><a class="btn" href="kontakt.html">Mehr</a></article>
<article class="card"><img src="img/b.jpg" alt="…"><h3>Umsetzung</h3><p>…</p><a class="btn" href="kontakt.html">Mehr</a></article>
<article class="card"><img src="img/c.jpg" alt="…"><h3>Übergabe</h3><p>…</p><a class="btn" href="kontakt.html">Mehr</a></article>
</div>
<!-- FALSCH: nur 2 Einträge (unsichere Gruppe) und abweichende Struktur
(Karte 2 ohne Bild, zusätzlicher Wrapper) -->
<div class="grid">
<article class="card"><img src="a.jpg" alt=""><h3>Planung</h3><p>…</p></article>
<div class="card special"><div class="inner"><h3>Umsetzung</h3></div></div>
</div>
3. ARIA-Konventionen #
ProntoSite wertet genau diese Attribute aus — mehr nicht:
| Attribut | Wirkung |
|---|---|
aria-controls (am Menü-Button) |
stärkstes Mobile-Menü-Signal |
aria-expanded |
Mobile-Menü-Signal |
aria-haspopup="true|menu|listbox" |
Untermenü-Kandidat (Dropdown NUR mit echter verschachtelter Linkliste) |
aria-hidden="true", role="presentation|none" |
Element gilt als Dekoration → gesperrt (nicht editierbar) |
aria-label |
editierbares Attribut-Feld; an Slider-Pfeilen zusätzlich Erkennungssignal (prev/next/…) |
alt, title, placeholder |
editierbare Attribut-Knoten |
label[for] / umschließendes <label> |
Feld-Beschriftung der Formular-Erkennung |
Achtung — häufigster Fehler: aria-hidden="true" auf INHALT (z. B. einem dekorativ animierten Titel) sperrt ihn für jede Bearbeitung. Verwende es nur für echte Dekoration (Icon-Glyphen, Zier-Elemente).
<!-- RICHTIG: dekoratives Icon versteckt, Inhalt frei -->
<i class="icon icon-star" aria-hidden="true"></i><h3>Bewertungen</h3>
<!-- FALSCH: die Überschrift ist damit gesperrt -->
<h3 aria-hidden="true">Bewertungen</h3>
4. CSS: Variablen-Token und Sanitisierung #
Regel Token: Definiere im Stylesheet :root-Variablen mit accent, primary oder brand im Namen; baue Buttons über eine Klasse mit btn, button oder cta; gib Hintergrundfarben von body/.hero/section als Hex-Wert an.
Warum: ProntoSite liest daraus die Optik der Website aus: die Akzentfarbe (--*accent|primary|brand*), border-radius, border, font-family, font-size (bevorzugt an body/p), die :focus-Outline, die häufigste btn/button/cta-Klasse an <a>/<button> und die background-color von body/.hero/section für die Hell/Dunkel-Einstufung. Aus diesen Werten entsteht die Optik neu eingefügter Formulare — sie fügen sich dann automatisch ins Design ein.
Regel Sanitisierung: Kein externes @import, kein expression(), kein behavior:, kein url(javascript:…) — diese werden beim Import entfernt (in .css-Dateien UND <style>-Blöcken). Alles andere CSS bleibt unangetastet. Liefere alle Styles lokal aus (Abschnitt 6).
/* RICHTIG */
:root { --primary: #1d4ed8; --accent: #f59e0b; }
body { font-family: "Inter", system-ui, sans-serif; font-size: 16px; background-color: #ffffff; }
.btn { background: var(--primary); border-radius: 6px; }
.btn:focus-visible { outline: 2px solid var(--accent); }
/* FALSCH: externes @import wird beim Import ENTFERNT → Optik bricht */
@import url("https://fonts.googleapis.com/css2?family=Inter");
5. Interaktionsmuster (Mobile-Menü, Dropdown, Slider, Akkordeon) #
Grundsatz: Du setzt keine data-ps-*-Attribute. ProntoSite erkennt die Muster rein strukturell und richtet die Interaktivität bei der Auslieferung selbst ein. So baust du die Muster, damit die Erkennung greift:
Mobile-Menü (Punktesystem: aria-controls wiegt am stärksten, dann Hamburger-Icon, aria-expanded, <button>; das Ziel muss auflösbar sein, sonst bleibt das Menü statisch):
<header>
<button class="burger" aria-controls="mainnav" aria-expanded="false">
<span></span><span></span><span></span> <!-- 3 gleiche leere Kinder = Hamburger -->
</button>
<nav id="mainnav">
<ul>
<li><a href="index.html">Start</a></li>
<li><a href="leistungen.html">Leistungen</a></li> <!-- ≥2 interne Links = Navigation -->
</ul>
</nav>
</header>
Mobile-Navigation = Drawer (Standard). Auf Smartphone/Tablet fährt das Menü als Drawer von rechts nach links herein – NICHT als Dropdown unter dem Header und NICHT als Vollbild-Overlay (das ist nicht der Default). Der Drawer ist position:fixed, volle Höhe, eigener z-index über dem Inhalt, und schließt per X-Button, Esc UND Klick auf den abgedunkelten Hintergrund (Backdrop). Auf dem Desktop bleibt die normale Menüleiste, Untermenüs als Dropdown (siehe unten).
So baust du den Toggle + Drawer, damit die Erkennung greift und das Verhalten stimmt:
<button class="burger" aria-controls="mainnav" aria-expanded="false">…</button>
<nav id="mainnav" class="drawer">…</nav>
- Toggle trägt
aria-expanded(Zustand) undaria-controls(Ziel-ID des Menüs). Optionaler expliziter Hinweis:data-ps-behavior="menu-toggle"– der Import entfernt das Attribut und verdrahtet strukturell neu;aria-controlsMUSS vorhanden sein (wiegt bei der Erkennung am stärksten). - Drawer im CSS bis zum Öffnen
display:nonebzw. ausgefahren (transform:translateX(100%)), Reveal über[aria-expanded="true"]am Auslöser (nicht über eine.open-Klasse – die setzt die Runtime nie). Einfahren pertransform-Transition. @media (prefers-reduced-motion: reduce)respektieren (keine/kurze Transition).
.drawer{position:fixed;inset:0 0 0 auto;width:min(86vw,360px);height:100%;z-index:1000;
transform:translateX(100%);transition:transform .25s ease;visibility:hidden}
[aria-expanded="true"] ~ .drawer,[aria-expanded="true"] + .drawer{transform:none;visibility:visible}
@media (prefers-reduced-motion: reduce){.drawer{transition:none}}
Dropdown (ein Menüpunkt mit ECHTER verschachtelter Linkliste; aria-haspopup allein reicht nicht):
<li><a href="leistungen.html">Leistungen</a>
<ul class="sub"><li><a href="malerarbeiten.html">Malerarbeiten</a></li>
<li><a href="bodenbelaege.html">Bodenbeläge</a></li></ul></li>
Slider/Karussell — die Signale müssen OHNE CSS erkennbar sein, denn Klassen-CSS wird für die Slider-Erkennung NICHT ausgewertet. Eines von drei Signalen genügt:
overflow:hiddenals Inline-Style am Container + mindestens 3 gleichartige Folien, ODER- Folien mit
position:absoluteals Inline-Style, ODER - Steuerungen als Geschwister der Folien: mindestens 2 Pfeile (
button/amitaria-label/Klasseprev/next/arrow/… oder Textzeichen‹ ›) oder ein Punkte-Container (mehrere kleine, textarme klickbare Kinder).
<!-- RICHTIG: Inline-overflow + 3 Folien + Pfeile -->
<div class="hero-slider" style="overflow:hidden">
<div class="slide"><img src="img/s1.jpg" alt="…"></div>
<div class="slide"><img src="img/s2.jpg" alt="…"></div>
<div class="slide"><img src="img/s3.jpg" alt="…"></div>
<button aria-label="Voriges">‹</button><button aria-label="Nächstes">›</button>
</div>
<!-- FALSCH: overflow nur im Stylesheet (.hero-slider{overflow:hidden}) → für die
Erkennung unsichtbar, ohne Pfeile/Punkte KEIN Slider → Folien stehen statisch untereinander -->
Akkordeon (mindestens 2 direkte Kind-Paare aus klickbarem Kopf — h1–h6, button, summary, a, dt — gefolgt von einem Inhaltscontainer div/section/dd/ul mit Inhalt):
<div class="faq">
<h3>Was kostet ein Anstrich?</h3><div><p>…</p></div>
<h3>Wie lange dauert es?</h3><div><p>…</p></div>
</div>
Ehrlichkeits-Netz: Klassen wie slider/carousel/accordion/tab/dropdown/collapse/menu/toggle oder data-toggle-artige Attribute OHNE erkennbares Muster erzeugen eine "konnte nicht sicher übernommen werden"-Meldung im Import-Bericht. Verwende solche Klassen also nur dort, wo das Muster wirklich erkennbar gebaut ist.
Rechner, Konfiguratoren und andere Skripte mit Werten #
Braucht eine Website ausnahmsweise eigenes JavaScript (z. B. Preisrechner, Konfigurator – nur mit JS-Freigabe der Website), gehören Preise, Sätze, Staffeln und Texte nicht ins Skript. Lege sie dort ab, wo sie ohne Code-Änderung pflegbar sind:
data--Attribute am Rechner-Element, die das Skript liest:<form class="rechner" data-grundpreis="150" data-preis-je-m2="12.5" data-waehrung="€">…</form> <p class="rechner-hinweis">Grundpreis 150 €, je m² 12,50 €</p>const el = document.querySelector(".rechner"); const grund = Number(el.dataset.grundpreis), jeM2 = Number(el.dataset.preisJeM2);oder eine
config.jsonneben dem Skript (relativer Pfad, kein fremder Host), die das Skript perfetch("config.json")lädt:{ "grundpreis": 150, "preisJeM2": 12.5, "waehrung": "€" }
Warum: Dann ändert eine Preisanpassung („150 → 250 €") nur HTML bzw. JSON – ohne jede Skript-Änderung, und Anzeige
und Rechnung können nicht auseinanderlaufen. Steht ein Wert doch im Skript, ändert ihn die KI mit site_edit_text
(siehe MCP: Preise und Texte in Skripten). Den sichtbaren Preis-Text (rechner-hinweis) und den Wert
gemeinsam pflegen: Text mit site_edit_text, das data--Attribut mit site_edit_html (z. B. data-grundpreis="150" →
data-grundpreis="250"), eine config.json mit site_file_put.
6. Assets: lokal, relativ, Favicon, Bildgrößen #
- Alles lokal, relative Pfade. Externe
https://…-Verweise (Bilder, CSS, Fonts,srcset,url()in<style>/style=) werden beim Import zwar best-effort lokalisiert (mit Grenze, Fehlschläge im Bericht) — ein Template sollte aber ab Werk null externe Verweise enthalten. - Favicon:
<link rel="icon" href="img/favicon.png">im<head>der Startseite, als lokale, mitgelieferte Datei.data:-URIs und externe URLs werden ignoriert. - Icons vs. Fotos: Als Icon gelten inline
<svg>, Icon-Font-Glyphen (<i class="fa-…">, leer) und<img>mit.svg-Quelle oderwidth/height≤ 64 — sie sind über die Icon-Bibliothek tauschbar. Größere Raster-Bilder gelten als Foto. Zeichne Fotos deshalb IMMER mitwidth/height> 64 bzw. ohne Icon-Klasse aus, Icons klein bzw. als Inline-SVG (siehe Abschnitt 10). - Hintergrundbilder:
style="background-image:url(img/…)"(inline) wird als Bild-Knoten erkannt und ist tauschbar; Hintergrundbilder, die NUR im Stylesheet stehen, sind nicht adressierbar. - Formate: übliche Web-Formate (jpg/png/webp/svg/avif); baue SVG-Dateien ohne
<script>/foreignObject.
7. Formulare #
ProntoSite erkennt Formulare vollständig: je input/select/textarea den Feldnamen (name, ersatzweise id), die Beschriftung (label[for] → umschließendes <label> → placeholder → aria-label), required, pattern und eine Consent-Checkbox (deren Label/Name datenschutz/einwillig/consent/agb/privacy enthält). Ein vorhandenes Formular dient außerdem als Stil-Vorlage für die ganze Website.
Konventionen fürs Template:
- Jedes Feld mit
name-Attribut (nurA–Z,a–z,0–9,_,-, max. 40 Zeichen) und echter<label for="…">-Beschriftung. - Pflichtfelder mit
required; eine Datenschutz-Checkbox mit sprechendem Namen (z. B.name="datenschutz") — sie wird als Consent erkannt. - Reserviert:
name="website"— das ist ein Honeypot-Feld zur Spam-Abwehr; Einsendungen mit gefülltemwebsite-Feld werden still verworfen. Nie als echtes Feld verwenden. - Submit als
<button type="submit">(Submit/Reset/Button werden nicht als Felder geführt).
Erfolgs-Weiterleitung (optional, empfohlen): Das <form> darf ein data-ps-redirect-Attribut mit site-internem Ziel tragen, z. B. data-ps-redirect="/beratung?gesendet=1". Nach erfolgreichem Versand leitet die Plattform dorthin weiter. Dein Template zeigt bei ?gesendet=1 seine Danke-Ansicht (per JS den Query-Parameter lesen und das Formular gegen eine Erfolgs-Box tauschen). Nur interne Pfade — externe URLs, javascript:/data: u. Ä. werden ignoriert (dann greift die eingebaute Erfolgsmeldung). Alternativen zum Attribut: ein verstecktes <input type="hidden" name="_redirect" value="/beratung?gesendet=1">; oder eine Query-only-action="?gesendet=1". Der Fehlerfall leitet nicht weiter, sondern zeigt die feldgenaue Fehlanzeige. Ohne Deklaration bleibt es bei der eingebauten Erfolgsmeldung.
<form action="" method="post" data-ps-redirect="/beratung?gesendet=1">
… Felder …
<button type="submit" class="btn">Absenden</button>
</form>
<!-- Danke-Ansicht des Templates (liest ?gesendet=1 und blendet die Erfolgs-Box ein): -->
<script>
if (new URLSearchParams(location.search).get("gesendet") === "1") {
document.querySelector("[data-form-danke]")?.removeAttribute("hidden");
document.querySelector("form")?.setAttribute("hidden", "");
}
</script>
Dein Formular bleibt deins. Bei einem eigenen Formular (importiert oder von der KI gebaut) übernimmt ProntoSite nur den Versand: action/method, versteckte Felder, Honeypot, Zeitprüfung und ein kleines Versand-Skript. Markup, Klassen und Styles des Formulars bleiben unverändert; die Rückmeldung nach dem Absenden erscheint als <div class="ps-form-msg ps-form-msg-ok|ps-form-msg-err" role="status"> mit Grundfarben ohne Gewicht (:where) – jede Regel deines CSS gewinnt. ProntoSite-eigenes Formular-Styling gibt es nur für Formulare, die ProntoSite erzeugt (Klasse ps-form).
Setze für die action zunächst action="" (oder #) — der Import lässt das unverändert; die Anbindung an den Mailweg erfolgt später über die Formular-Registrierung und wird nicht im Template hartkodiert (die Kunden-Zuordnung ist zur Template-Zeit unbekannt).
<form action="" method="post">
<label for="f-name">Ihr Name</label>
<input id="f-name" name="name" type="text" required>
<label for="f-mail">E-Mail</label>
<input id="f-mail" name="email" type="email" required>
<label><input type="checkbox" name="datenschutz" required> Ich habe die Datenschutzerklärung gelesen.</label>
<button type="submit" class="btn">Absenden</button>
</form>
8. Verbotenes #
Alles hier wird beim Import entfernt oder führt zu Berichts-Warnungen:
- Eigenes JavaScript — jedes
<script>(inline und extern) wird entfernt;on*-Handler undjavascript:-URLs werden gestrippt..js-Dateien im ZIP werden gar nicht übernommen, ebenso.php/.asp/… - Nicht sicher einbettbare iframes — iframes mit
https://-Quelle bleiben erhalten: Nicht freigegebene Anbieter werden eng gesandboxt (allow-scripts allow-same-origin) und laden erst nach Einwilligung; freigegebene (YouTube, Vimeo, Google Maps, Calendly, resmio) bekommen zusätzlich ihre passende Sandbox, YouTube wird zu youtube-nocookie. Entfernt und durch einen Kommentar-Platzhalter ersetzt werden nur iframes ohnehttps://-Quelle (auch reinesrcdoc-iframes) sowie JEDES<object>/<embed>; der Import-Bericht nennt sie. - JS-abhängige Dritt-Widgets — externe URLs in
data-*-Attributen erzeugen eine "bleibt statisch leer"-Warnung. Keine Lazy-Load-data-src-Muster, keinedata-settings-Widgets: Bilder direkt insrc. data-ps-*-Attribute selbst setzen — dieser Namensraum gehört der Plattform (siehe Abschnitt 5); eigene Werte kollidieren mit der automatischen Auszeichnung. Erlaubt bleiben das suffixlosedata-ps-Attribut für die dokumentierten Marker (Abschnitt 12) – darunterimpressum/datenschutz, die Footer-Links und das Footer-Badgedata-ps="badge"– sowie die Konfig-Attributedata-ps-variant(Badge),data-ps-zoom(Bild-Zoom) unddata-ps-redirect(Formular).- Keine Bootstrap-
data-bs-toggle-Mechanik erwarten: Ohne JavaScript zählt allein die statische Struktur aus Abschnitt 5. - Rechtstext-Formulierungen in normalen Seiten — Slugs/Dateinamen/Titel wie
impressum/datenschutz/agb/… und massierte §-Formulierungen im Hauptinhalt sperren die GANZE Seite für die Bearbeitung. Das ist für echte Rechtsseiten gewollt (ein Platzhalter-Impressum ins Template zu legen ist richtig) — verwende solche Begriffe aber niemals in Marketing-Slugs.
Sandbox eingebetteter iframes: Die Plattform setzt das sandbox-Attribut selbst, ein eigener Wert im Template wird überschrieben. Beim Veröffentlichen bekommen iframes mit allow-popups und anderem Origin als die Website zusätzlich allow-popups-to-escape-sandbox, damit Links mit target="_blank" aus dem Widget normale Tabs öffnen. Die Sandbox des Widgets selbst bleibt bestehen.
9. Abnahme-Test (je Template, vor Aufnahme in die Galerie) #
- ZIP bauen (ein gemeinsamer Wurzelordner wird erkannt):
cd template-x && zip -r ../template-x.zip . - Import ausführen: "Meine Websites" → "+ Neue Website" → ZIP-Import.
- Import-Bericht lesen — für ein sauberes Template erwartet: keine entfernten Skripte (oder bewusst, dann prüfen was fehlt), keine entfernten Embeds, keine dynamischen Widgets, keine fehlgeschlagenen Lokalisierungen, korrekte Sprachen, alle Seiten vorhanden.
- Prüfansicht je Seite prüfen: Navigation erkannt, erwartete Anzahl Gruppen, Interaktionen (mobile-menu/dropdown/slider/accordion) wie gebaut, Formulare erkannt; unter "nicht erkannt" nur bewusste Sonder-Sektionen, keine unsicheren Gruppen (sonst 3. Eintrag ergänzen), keine unerkannten Muster.
- Vorschau bedienen: Mobile-Menü öffnen/schließen (Tastatur: Enter/Escape), Dropdown, Slider-Pfeile, Akkordeon — die Muster müssen in der Vorschau funktionieren (identisch im veröffentlichten Stand).
- Editor-Durchstich: eine Überschrift ändern, eine Karte duplizieren, ein Icon tauschen, ein Bild tauschen, Undo.
- Bausteine-Tab öffnen: die erwarteten Karten/Boxen erscheinen als Bausteine mit echter Miniatur (Abschnitt 10); einen Baustein testweise auf einer anderen Seite einfügen.
- Publish prüfen: Veröffentlichen; die veröffentlichte Fassung enthält das Original bytetreu.
10. Bausteine-Tauglichkeit (Bibliothek + kontextfreie Optik) #
Regel A — als Baustein qualifizieren: Ein Eintrag einer Wiederholungsgruppe wird nur dann Bibliotheks-Baustein, wenn er inhaltlich eigenständig ist: Bild ODER Überschrift plus mindestens ein weiterer Inhaltstyp (bzw. mindestens 3 Elemente); Icon+Text; Formular; oder eine mehrteilige Textbox (mindestens 3 Elemente, mindestens 40 Zeichen). Reine Text-/Link-Listenpunkte werden bewusst NICHT aufgenommen. Außerdem darf der Eintrag kein Seitenbereich direkt unter body/main sein (ein section/header/footer/… auf oberster Ebene wird kein Baustein) — lege Karten also immer in einen Container (div.grid o. ä.).
Regel B — Optik an der EIGENEN Klasse: Der komplette Stil einer Karte muss an ihrer eigenen Klasse hängen (.card { … }), nie an Eltern-Selektoren (.grid > div { … }). Beim Einfügen an fremder Stelle warnt ProntoSite zwar, wenn die neue Umgebung Layout-Klassen trägt — aber das ERGEBNIS stimmt nur, wenn die Karte sich selbst trägt.
Regel C — identischer Inhalt = konstanter Baustein: Sind die Einträge einer Gruppe site-weit wortgleich (z. B. eine Kontaktbox auf mehreren Seiten), wird der Baustein mit Inhalt übernommen; sonst bekommen Klone Platzhalter. Schreibe Kontaktboxen deshalb überall byte-gleich (siehe Abschnitt 11).
Regel D — Icons als Inline-SVG: Bette Icons in Karten/Icon-Listen als <svg …> inline ein (oder als leeres Icon-Font-<i>): So werden sie als Icon erkannt und sind gegen die Bibliothek tauschbar (Inline-SVG wird 1:1 ersetzt, Größe/Klassen bleiben). Ein Foto-<img> lässt sich zwar auch tauschen, aber die Icon-Erkennung und die Rollen-Benennung ("Icon-Karte") greifen nur bei echten Icon-Elementen.
<!-- RICHTIG: eigenständige Icon-Karte, Stil an .icard, Inline-SVG -->
<div class="icards">
<div class="icard">
<svg class="icon" width="32" height="32" viewBox="0 0 24 24" aria-hidden="true"><path d="…"/></svg>
<h3>Beratung</h3><p>Persönlich und vor Ort.</p>
</div>
<!-- … 2 weitere gleich gebaute … -->
</div>
/* RICHTIG: die Karte trägt sich selbst */
.icard { background:#fff; border-radius:8px; padding:24px; box-shadow:0 2px 8px rgba(0,0,0,.08); }
/* FALSCH: Optik hängt am Eltern-Kontext – eingefügt anderswo bricht sie */
.icards > div { background:#fff; border-radius:8px; }
11. Reichweiten-Freundlichkeit (wiederholte Inhalte) #
Regel: Führe Telefonnummer, Öffnungszeiten, Adresse und ähnliche site-weite Angaben auf ALLEN Seiten in identischer Schreibweise — inklusive der tel:-/mailto:-Links (sichtbarer Text UND href konsistent).
Warum: ProntoSite erkennt wiederkehrende Inhalte über einen normalisierten Vergleich. Toleriert werden daher nur Unterschiede in Interpunktion und Leerraum ("0175-999 88 77" ≡ "0175 – 999 88 77"); abweichende Ziffern-Gruppierung oder Wortlaut zerreißen den Inhalt in getrennte Fundstellen ("0175 9998877" ≠ "0175 999 88 77"; "Mo–Fr 8–17 Uhr" ≠ "Montag bis Freitag 8 bis 17 Uhr"). Dann bietet das System nicht mehr "überall ändern?" an, sondern sieht verschiedene Inhalte. tel:-Links werden bei "überall" nur dann konsistent nachgezogen, wenn das href bereits mit tel: beginnt.
<!-- RICHTIG: überall exakt gleich, tel:-Link konsistent (alle Seiten!) -->
<div class="topbar"><span>Mo.–Fr. 8–17 Uhr</span>
<a href="tel:+4922855544">0228 555 44</a></div>
…
<footer><p>Mo.–Fr. 8–17 Uhr · <a href="tel:+4922855544">0228 555 44</a></p></footer>
<!-- FALSCH: drei Schreibweisen derselben Nummer → drei getrennte „Inhalte" -->
<span>0228/55544</span> … <span>0228 555 44</span> … <a href="tel:022855544">Ruf an!</a>
12. Marker & Shortcodes #
Mit Markern (HTML-Kommentaren bzw. dem einen erlaubten data-ps-Attribut) platzierst du an gewünschter Stelle Plattform-Elemente wie ein Kontaktformular, das Google-Bewertungs-Widget, einen Inline-Hinweis (data-ps="hinweis") oder generierte Rechtstexte (Impressum, Datenschutz) sowie deren Links. Sie verletzen die data-ps-*-Regel aus Abschnitt 8 nicht. Manche Plattform-Elemente – etwa Hinweise als Modal/Banner oder das Cookie-Banner – brauchen keinen Marker; sie werden allein im Dashboard aktiviert.
Details und die vollständige Marker-Liste unter Marker & Shortcodes.
Pflicht-Marker (Rechtsseiten & Footer) #
Rechtsseiten. impressum/index.html und datenschutz/index.html enthalten IMMER den Inhaltsbereich als Rollen-Marker – <div data-ps="impressum"> bzw. <div data-ps="datenschutz"> – und bringen ihre eigene <h1> mit. Schreibe keinen Rechtstext von Hand hinein (ProntoSite generiert ihn in den Marker). Weil die Seite ihre eigene Überschrift hat, die Widget-Überschrift deaktivieren: im Dashboard-Toggle „Überschrift anzeigen" aus bzw. über die API site_legal_options mit showTitle:false. (Beim Erst-Import mit ?markers=auto setzt ProntoSite showTitle:false automatisch, sobald die Rechtsseite eine eigene <h1> hat.)
<!-- impressum/index.html -->
<main><h1>Impressum</h1><div data-ps="impressum"></div></main>
Footer. Jeder Footer enthält IMMER alle vier Rechts-/Consent-Marker:
<a data-ps="link-impressum">Impressum</a>
<a data-ps="link-datenschutz">Datenschutz</a>
<a data-ps="cookie-einstellungen">Cookie-Einstellungen</a>
<a data-ps="cookie-richtlinie">Cookie-Richtlinie</a>
Fehlen die Cookie-Links, hängt das Consent-Widget sonst einen ungestylten Block an den Seitenfuß. Mehrsprachig: dieselben vier Marker je Sprach-Footer, nur der sichtbare Linktext lokalisiert.
Badge (optional, empfohlen). Das Footer-Badge „Made with ProntoSite" (einheitlich in allen Sprachen) erscheint nur, wenn du den Marker setzt – es gibt kein automatisches Badge. Platzierung: Footer, letzte Zeile, bündig mit dem Copyright. ProntoSite bringt jedes data-ps="badge" beim Ausliefern auf die kanonische Form (Icon + Text, Systemschrift 12 px, eigene Styles des Templates greifen nicht); wählbar ist nur die Farbe per data-ps-variant (auto = Footer-Textfarbe, light, dark, mono). Nie selbst stylen und kein eigenes Icon per CSS oder <img> – siehe Badge.
<a data-ps="badge" data-ps-variant="auto" href="https://prontosite.io/?ref=badge&site=SLUG" rel="noopener noreferrer">Made with ProntoSite</a>
Bild-Zoom (optional). Bilder mit data-ps-zoom bzw. alle Bilder in einem Container mit der Klasse ps-gallery öffnen per Klick die Lightbox der ProntoSite-Runtime (Galerie-Blättern innerhalb desselben Containers). Kein eigenes Lightbox-Skript einbauen – siehe Bilder per Klick vergrößern.
13. Kurzfassung (Prompt für die KI / Schnell-Check) #
Baue eine statische Website (nur HTML/CSS, kein JavaScript nötig – es würde beim Import entfernt). Falls doch ein Rechner/Konfigurator mit Skript nötig ist: Preise und Werte NIE im JS hartkodieren, sondern als
data--Attribute am Element oder in einerconfig.jsonablegen, die das Skript liest. Semantische Struktur, relative Asset-Pfade (css/…,../fonts/…, nie/css/…absolut). Keinedata-ps-*-Attribute außer den erlaubten Markern. Mobile-Navigation = Drawer: Menü fährt auf Smartphone/Tablet von rechts herein (position:fixed, volle Höhe, eigener z-index), schließt per X-Button,Escund Klick auf den abgedunkelten Hintergrund – kein Dropdown unter dem Header, kein Vollbild-Overlay. Toggle:aria-expanded+aria-controls, Drawer bis zum Öffnen versteckt, Reveal über[aria-expanded="true"], Einfahren pertransform-Transition,prefers-reduced-motionrespektieren. Desktop: normale Leiste, Untermenüs als Dropdown. Rechtsseiten:impressum/index.htmlunddatenschutz/index.htmlenthalten IMMER<div data-ps="impressum">bzw.<div data-ps="datenschutz">als Inhaltsbereich und eine eigene<h1>; kein handgeschriebener Rechtstext; Widget-Überschrift aus (showTitle:false). Footer: IMMER alle vier Marker<a data-ps="link-impressum">,<a data-ps="link-datenschutz">,<a data-ps="cookie-einstellungen">,<a data-ps="cookie-richtlinie">(sonst hängt das Consent-Widget einen ungestylten Block an); mehrsprachig je Sprach-Footer dieselben Marker, Linktext lokalisiert. Optional + empfohlen: das Badge „Made with ProntoSite" per<a data-ps="badge"></a>im Footer neben die Rechts-Links setzen (erscheint nur mit Marker, tarif-unabhängig).