77 changed files with 47358 additions and 92 deletions
@ -0,0 +1,40 @@ |
|||
# 01 - Úvod do HTML |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se seznámíte se základy HTML a strukturou webové stránky. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Základní struktura HTML dokumentu** (`<!DOCTYPE html>`, `<html>`, `<head>`, `<body>`) |
|||
- **Nadpisy** (`<h1>` až `<h6>`) |
|||
- **Odstavce** (`<p>`) |
|||
- **Odkazy** (`<a href="">`) |
|||
- **Obrázky** (`<img src="" alt="">`) |
|||
- **Komentáře v HTML** (`<!-- komentář -->`) |
|||
- **Zalomení řádku** (`<br>`) |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - hlavní HTML soubor s ukázkami základních HTML tagů |
|||
- `about.html` - další stránka pro demonstraci odkazů |
|||
- `profily/` - složka s příklady vnořené struktury souborů |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči (dvojklik nebo přes Live Server) |
|||
2. Prohlédněte si HTML kód v editoru |
|||
3. Zkuste upravit texty, přidat nové nadpisy nebo odstavce |
|||
4. Vyzkoušejte vytvořit vlastní odkazy na nové stránky |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- Používejte komentáře (`<!-- -->`) pro poznámky v kódu |
|||
- Zkratka pro zakomentování: `CTRL+K CTRL+C` (odkomentování: `CTRL+K CTRL+U`) |
|||
- Každý tag, který otevřete, musíte i zavřít (např. `<p>...</p>`) |
|||
- Atribut `alt` u obrázků je povinný (popisuje obrázek) |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Další:** 02 - pokračování v HTML |
|||
- **Související:** 03_css_uvod - stylování HTML elementů |
|||
@ -0,0 +1,124 @@ |
|||
# 02 - HTML Pokročilé Elementy |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte pracovat s pokročilejšími HTML elementy a Emmet zkratkami. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Tabulky** (`<table>`, `<tr>`, `<td>`, `<th>`) |
|||
- Struktura tabulek |
|||
- Řádky (`<tr>`) a buňky (`<td>`) |
|||
- Nadpisy tabulek (`<th>`) |
|||
- Stylování pomocí inline CSS |
|||
- **Seznamy** (`<ul>`, `<ol>`, `<dl>`) |
|||
- Nečíslované seznamy (`<ul>`) |
|||
- Číslované seznamy (`<ol>`) |
|||
- Definiční seznamy (`<dl>`, `<dt>`, `<dd>`) |
|||
- **Emmet zkratky** - rychlé psaní HTML |
|||
- **ALT + klikání** - multi-cursor editing |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - hlavní soubor s ukázkami |
|||
- `formular.html` - příklad formuláře |
|||
|
|||
## 💻 Ukázky z lekce |
|||
|
|||
### Tabulka: |
|||
```html |
|||
<table style="border: 2px black solid;"> |
|||
<tr> |
|||
<th>Jméno</th> |
|||
<th>Částka</th> |
|||
<th>Měna</th> |
|||
</tr> |
|||
<tr> |
|||
<td>Martin</td> |
|||
<td>50</td> |
|||
<td>$</td> |
|||
</tr> |
|||
</table> |
|||
``` |
|||
|
|||
### Seznamy: |
|||
```html |
|||
<!-- Nečíslovaný seznam --> |
|||
<ul> |
|||
<li>První položka</li> |
|||
<li>Druhá položka</li> |
|||
</ul> |
|||
|
|||
<!-- Číslovaný seznam --> |
|||
<ol> |
|||
<li>První krok</li> |
|||
<li>Druhý krok</li> |
|||
</ol> |
|||
|
|||
<!-- Definiční seznam --> |
|||
<dl> |
|||
<dt>HTML</dt> |
|||
<dd>- HyperText Markup Language</dd> |
|||
<dt>CSS</dt> |
|||
<dd>- Cascading Style Sheets</dd> |
|||
</dl> |
|||
``` |
|||
|
|||
### Emmet zkratky: |
|||
``` |
|||
ul>li*5>a → vytvoří <ul> s 5 <li>, každý obsahuje <a> |
|||
table>tr*3>td*4 → vytvoří tabulku 3 řádky × 4 sloupce |
|||
p>a → vytvoří <p> s <a> uvnitř |
|||
html:5 nebo ! → vytvoří HTML5 šablonu |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Prohlédněte si ukázky tabulek a seznamů |
|||
3. Zkuste vytvořit vlastní tabulku s více řádky a sloupci |
|||
4. Vyzkoušejte Emmet zkratky v editoru |
|||
5. Použijte **ALT + klikání** pro psaní na více místech najednou |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Struktura tabulky: |
|||
``` |
|||
<table> ← kontejner tabulky |
|||
<tr> ← řádek (Table Row) |
|||
<th> ← hlavička (Table Header) |
|||
<td> ← buňka (Table Data) |
|||
``` |
|||
|
|||
### Emmet zkratky - příklady: |
|||
- **`html:5`** nebo **`!`** - vytvoří HTML5 šablonu |
|||
- **`ul>li*5`** - vytvoří `<ul>` s 5 `<li>` elementy |
|||
- **`div.class#id`** - vytvoří `<div class="class" id="id">` |
|||
- **`table>tr*3>td*4`** - tabulka 3×4 |
|||
- **`h1+p+p`** - `<h1>` a dva `<p>` za sebou |
|||
|
|||
### Multi-cursor (ALT + klikání): |
|||
- Držte **ALT** a klikejte na různá místa |
|||
- Můžete psát text na více místech najednou |
|||
- Užitečné pro opakující se text |
|||
|
|||
### Inline CSS: |
|||
```html |
|||
<!-- Inline CSS přímo v elementu --> |
|||
<h1 style="color: lime; background-color: purple;">Nadpis</h1> |
|||
|
|||
<!-- Lepší je CSS v samostatném souboru (naučíte se v lekci 03) --> |
|||
``` |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
- Tabulky se dnes používají **pouze pro tabulková data**, ne pro layout |
|||
- Pro layout použijte **CSS Grid** nebo **Flexbox** (naučíte se později) |
|||
- **Emmet** je součástí většiny editorů (VS Code, Sublime, Atom) |
|||
- Inline CSS je OK pro testování, ale pro produkci použijte externí CSS |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 01_uvod - základy HTML |
|||
- **Další:** 03_css_uvod - stylování pomocí CSS |
|||
- **Emmet dokumentace:** [Emmet Cheat Sheet](https://docs.emmet.io/cheat-sheet/) |
|||
@ -0,0 +1,53 @@ |
|||
# 03 - Úvod do CSS |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte základy CSS (Cascading Style Sheets) - stylování webových stránek. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Připojení CSS** k HTML (external, internal, inline) |
|||
- **CSS selektory** (element, třída `.class`, ID `#id`) |
|||
- **Barvy** (`color`, `background-color`) |
|||
- **Text styling** (velikost, barva, zarovnání) |
|||
- **Kombinace tříd** (více tříd na jednom elementu) |
|||
- **Stylování seznamů a tabulek** |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML dokument s různými elementy |
|||
- `style.css` - CSS soubor s definicemi stylů |
|||
|
|||
## 🎨 Ukázky v lekci |
|||
|
|||
```css |
|||
/* Stylování třídou */ |
|||
.fancyText { color: blue; } |
|||
|
|||
/* Stylování ID */ |
|||
#uniqueElement { font-size: 20px; } |
|||
|
|||
/* Kombinace tříd */ |
|||
.fancyText.fancyBG { ... } |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Prozkoumejte soubor `style.css` - zde jsou definovány styly |
|||
3. V HTML najděte atributy `class=""` a `style=""` - propojení s CSS |
|||
4. Zkuste změnit barvy, velikosti nebo přidat nové třídy |
|||
5. Vyzkoušejte kombinovat více tříd na jednom elementu |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- **Inline CSS** (`style=""` přímo v HTML) - použijte jen výjimečně |
|||
- **External CSS** (samostatný soubor) - nejlepší pro větší projekty |
|||
- **Třída** (`.class`) - pro opakující se styly (můžete použít vícekrát) |
|||
- **ID** (`#id`) - pro unikátní element (použijte jen jednou na stránce) |
|||
- Element může mít více tříd najednou: `class="fancyText fancyBG"` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 01_uvod, 02 - základy HTML |
|||
- **Další:** 04_layout - pokročilejší layout techniky |
|||
@ -0,0 +1,45 @@ |
|||
# 04 - CSS Layout |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet layout (rozvržení) webové stránky pomocí CSS. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Box Model** (margin, padding, border) |
|||
- **Display property** (`block`, `inline`, `inline-block`) |
|||
- **Float** (obtékání elementů) |
|||
- **Clear** (ukončení obtékání) |
|||
- **Width a Height** (šířka a výška elementů) |
|||
- **Základní layouty** (dvousloupcový, třísloupcový) |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML struktura s layoutem |
|||
- `style.css` nebo `css/` složka - CSS styly pro layout |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Prozkoumejte CSS - zaměřte se na vlastnosti `float`, `clear`, `width` |
|||
3. Použijte Developer Tools (F12) a vyzkoušejte Box Model vizualizaci |
|||
4. Zkuste změnit šířky sloupců a sledujte, jak se mění layout |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- **Box Model**: `margin` (vnější odsazení) ≠ `padding` (vnitřní odsazení) |
|||
- **Float** je starší technika - dnes se používá spíše Flexbox nebo Grid |
|||
- Nezapomeňte používat `clear: both;` po float elementech |
|||
- Developer Tools (F12) jsou váš nejlepší přítel pro debugování layoutu |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
- Float-based layout je starší přístup |
|||
- V moderních projektech se používá **Flexbox** (lekce 10) nebo **Grid** (lekce 12) |
|||
- Tato lekce je důležitá pro pochopení starších projektů |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 03_css_uvod - základy CSS |
|||
- **Další:** 10_flex - moderní flexbox layout |
|||
- **Související:** 12_grid - CSS Grid systém |
|||
@ -0,0 +1,71 @@ |
|||
# 05 - Úvod do JavaScriptu |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se seznámíte se základy programování v JavaScriptu. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Připojení JavaScriptu** k HTML (inline, external) |
|||
- **Console.log** - výpis do konzole (F12) |
|||
- **Proměnné** (`let`, `const`, `var`) |
|||
- **Datové typy**: |
|||
- Čísla (number) |
|||
- Texty (string) |
|||
- Pole (array) |
|||
- Objekty (object) |
|||
- Datum (Date) |
|||
- **Podmínky** (`if`, `else`, `&&`, `||`) |
|||
- **Cykly** (`for`) |
|||
- **Funkce** (definice a volání) |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML soubor s připojením JS |
|||
- `app.js` - JavaScript soubor s ukázkami základů |
|||
|
|||
## 💻 Ukázky v lekci |
|||
|
|||
```javascript |
|||
// Proměnné |
|||
let x = 5; |
|||
const jmeno = "Jan"; |
|||
|
|||
// Podmínky |
|||
if (x > 3) { |
|||
console.log("x je větší než 3"); |
|||
} |
|||
|
|||
// Funkce |
|||
function pozdrav() { |
|||
console.log("Ahoj!"); |
|||
} |
|||
pozdrav(); // volání funkce |
|||
|
|||
// Cyklus |
|||
for (let i = 0; i < 5; i++) { |
|||
console.log(i); |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Otevřete **Developer Console** (F12 → záložka Console) |
|||
3. Prohlédněte si soubor `app.js` v editoru |
|||
4. Zkuste měnit hodnoty proměnných a sledujte výstup v konzoli |
|||
5. Vytvořte vlastní funkce a zavolejte je |
|||
6. Experimentujte s podmínkami a cykly |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- **Console.log()** je váš nejlepší přítel při debugování |
|||
- **let** vs **const**: použijte `const` pro hodnoty, které se nemění |
|||
- **var** se dnes už moc nepoužívá - používejte `let` nebo `const` |
|||
- Nezapomeňte volat funkci pomocí závorek: `nazevFunkce()` |
|||
- Pro objekty používáme tečkovou notaci: `osobnost.jmeno` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Další:** 06_js_html - propojení JavaScriptu s HTML elementy |
|||
- **Související:** 07_js_css_dom - manipulace s CSS přes JavaScript |
|||
@ -0,0 +1,62 @@ |
|||
# 06 - JavaScript a HTML |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte propojit JavaScript s HTML elementy a vytvořit interaktivní kalkulačku. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **getElementById()** - získání elementu podle ID |
|||
- **innerHTML** - změna obsahu elementu |
|||
- **innerText** - změna textu elementu |
|||
- **onclick** - obsluha kliknutí na tlačítko |
|||
- **Input elementy** - čtení hodnot z formulářových polí |
|||
- **Number()** - převod textu na číslo |
|||
- **Matematické operace** v JavaScriptu |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s inputy a tlačítky |
|||
- `js/app.js` - JavaScript s funkcí pro výpočet |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```html |
|||
<!-- HTML --> |
|||
<input type="number" id="num1" placeholder="Číslo 1"> |
|||
<button onclick="vypocitat('+')">SEČÍST</button> |
|||
<span id="vysledek"></span> |
|||
``` |
|||
|
|||
```javascript |
|||
// JavaScript |
|||
function vypocitat(operator) { |
|||
let cislo1 = document.getElementById("num1").value; |
|||
let cislo2 = document.getElementById("num2").value; |
|||
// výpočet a zobrazení výsledku |
|||
document.getElementById("vysledek").innerHTML = vysledek; |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Vyzkoušejte kalkulačku - zadejte čísla a klikněte na tlačítka |
|||
3. Otevřete `js/app.js` a prozkoumejte funkci `vypocitat()` |
|||
4. Sledujte, jak se hodnoty čtou z inputů pomocí `getElementById()` |
|||
5. Zkuste přidat další operace (mocnina, odmocnina) |
|||
6. Použijte Developer Console (F12) pro debugování |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- **getElementById()** vrací element, ne hodnotu - musíte použít `.value` |
|||
- **onclick** můžete použít přímo v HTML: `onclick="nazevFunkce()"` |
|||
- Hodnoty z inputů jsou vždy **string** - použijte `Number()` pro převod |
|||
- **innerHTML** vs **innerText**: innerHTML umožňuje HTML tagy, innerText jen text |
|||
- Používejte **console.log()** pro kontrolu hodnot při vývoji |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 05_js_intro - základy JavaScriptu |
|||
- **Další:** 07_js_css_dom - manipulace s CSS přes JavaScript |
|||
- **Související:** 08_js_form - práce s formuláři |
|||
@ -0,0 +1,85 @@ |
|||
# 07 - JavaScript, CSS a DOM |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte měnit CSS styly pomocí JavaScriptu a pracovat s DOM (Document Object Model). |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **DOM (Document Object Model)** - struktura HTML v JavaScriptu |
|||
- **style.property** - změna CSS vlastností přes JS |
|||
- **onchange** event - reakce na změnu hodnoty |
|||
- **Select element** - práce s rozbalovacím seznamem |
|||
- **Input type="color"** - barevný picker |
|||
- **Dynamická změna stylů** (barva textu, barva pozadí, font) |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s select elementy a color pickery |
|||
- `css/style.css` - základní CSS styly |
|||
- `js/index.js` - JavaScript pro změnu barev |
|||
- `js/changeFont.js` - JavaScript pro změnu fontu |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```html |
|||
<!-- HTML --> |
|||
<p id="ltext">Lorem ipsum...</p> |
|||
<select id="scolor" onchange="changeSColor()"> |
|||
<option value="black">černá</option> |
|||
<option value="red">červená</option> |
|||
</select> |
|||
<input type="color" id="tcolor" onchange="dynColor()"> |
|||
``` |
|||
|
|||
```javascript |
|||
// JavaScript |
|||
function changeSColor() { |
|||
let element = document.getElementById("ltext"); |
|||
let barva = document.getElementById("scolor").value; |
|||
element.style.color = barva; |
|||
} |
|||
|
|||
function dynColor() { |
|||
let element = document.getElementById("ltext"); |
|||
let barva = document.getElementById("tcolor").value; |
|||
element.style.color = barva; |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Vyzkoušejte měnit barvu textu pomocí selectu a color pickeru |
|||
3. Změňte font pomocí selectu |
|||
4. Prozkoumejte JS soubory - jak se elementy mění pomocí `.style` |
|||
5. Zkuste přidat další styly (velikost textu, tučnost, kurzíva) |
|||
6. Experimentujte s různými CSS vlastnostmi |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- **element.style.property** - property musí být v camelCase: |
|||
- CSS: `background-color` → JS: `backgroundColor` |
|||
- CSS: `font-size` → JS: `fontSize` |
|||
- **onchange** se spouští při změně hodnoty (select, input) |
|||
- **input type="color"** vrací hodnotu v HEX formátu (#000000) |
|||
- Používejte **Developer Tools** (F12) → Elements → Styles pro inspekci CSS |
|||
|
|||
## 🎨 CSS vlastnosti, které můžete měnit přes JS |
|||
|
|||
```javascript |
|||
element.style.color = "red"; |
|||
element.style.backgroundColor = "blue"; |
|||
element.style.fontSize = "20px"; |
|||
element.style.fontFamily = "Arial"; |
|||
element.style.fontWeight = "bold"; |
|||
element.style.textAlign = "center"; |
|||
element.style.padding = "10px"; |
|||
element.style.margin = "5px"; |
|||
``` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 06_js_html - propojení JS a HTML |
|||
- **Další:** 08_js_form - validace formulářů s JavaScriptem |
|||
- **Související:** 05_js_intro - základy JavaScriptu |
|||
@ -0,0 +1,94 @@ |
|||
# 08 - JavaScript a Formuláře |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte pracovat s formuláři v JavaScriptu - validace, odeslání, manipulace s daty. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Formulářové elementy** (input, textarea, select, checkbox, radio) |
|||
- **Validace formulářů** s JavaScriptem |
|||
- **event.preventDefault()** - zabránění odeslání formuláře |
|||
- **Čtení hodnot** z různých typů inputů |
|||
- **Kontrola povinných polí** |
|||
- **Regex** (základy) - kontrola formátu emailu, telefonu |
|||
- **Visual feedback** - zobrazení chyb uživateli |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML formulář |
|||
- `js/` - JavaScript soubory pro validaci |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```html |
|||
<!-- HTML --> |
|||
<form id="myForm" onsubmit="return validateForm()"> |
|||
<input type="text" id="jmeno" required> |
|||
<input type="email" id="email" required> |
|||
<button type="submit">Odeslat</button> |
|||
</form> |
|||
<p id="error"></p> |
|||
``` |
|||
|
|||
```javascript |
|||
// JavaScript |
|||
function validateForm() { |
|||
let jmeno = document.getElementById("jmeno").value; |
|||
let email = document.getElementById("email").value; |
|||
|
|||
if (jmeno === "") { |
|||
document.getElementById("error").innerHTML = "Jméno je povinné!"; |
|||
return false; // zabrání odeslání |
|||
} |
|||
|
|||
// Regex pro email |
|||
let emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
|||
if (!emailRegex.test(email)) { |
|||
document.getElementById("error").innerHTML = "Neplatný email!"; |
|||
return false; |
|||
} |
|||
|
|||
return true; // formulář se odešle |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Vyzkoušejte odeslat formulář s prázdnými poli |
|||
3. Sledujte validační zprávy |
|||
4. Prozkoumejte JS kód - jak funguje validace |
|||
5. Zkuste přidat další validace (délka hesla, shoda hesel) |
|||
6. Použijte console.log() pro debugování |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- **return false** v `onsubmit` zabrání odeslání formuláře |
|||
- **event.preventDefault()** je modernější způsob zabránění odeslání |
|||
- **required** atribut v HTML je první úroveň validace (HTML5) |
|||
- **JavaScript validace** je důležitá pro pokročilejší kontroly |
|||
- **Regex** (regulární výrazy) jsou mocný nástroj pro validaci formátů |
|||
- Vždy validujte i na **serveru** - JavaScript validace lze obejít |
|||
|
|||
## 🔍 Užitečné Regex vzory |
|||
|
|||
```javascript |
|||
// Email |
|||
/^[^\s@]+@[^\s@]+\.[^\s@]+$/ |
|||
|
|||
// Telefon (CZ formát) |
|||
/^(\+420)?[0-9]{9}$/ |
|||
|
|||
// Heslo (min 8 znaků, velké, malé, číslo) |
|||
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/ |
|||
|
|||
// Poštovní směrovací číslo |
|||
/^[0-9]{3}\s?[0-9]{2}$/ |
|||
``` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 07_js_css_dom - manipulace s CSS |
|||
- **Související:** AI/ai_03_form_validation - pokročilá validace s addEventListener |
|||
- **Další:** 11_json - práce s JSON daty |
|||
@ -0,0 +1,100 @@ |
|||
# 09 - Media Queries a Responzivní Design |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet responzivní webové stránky pomocí media queries. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Media Queries** - CSS pravidla pro různé velikosti obrazovek |
|||
- **Viewport meta tag** - důležitý pro responzivitu |
|||
- **Breakpointy** - body zlomu pro různá zařízení |
|||
- **Mobile-first přístup** vs Desktop-first |
|||
- **Responzivní obrázky** - přizpůsobení velikosti |
|||
- **Responzivní layout** - změna rozvržení podle velikosti |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s viewport meta tagem |
|||
- `style.css` - CSS s media queries |
|||
- `img/` - složka s obrázky |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```html |
|||
<!-- HTML - DŮLEŽITÝ viewport meta tag! --> |
|||
<head> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
``` |
|||
|
|||
```css |
|||
/* CSS - Media Queries */ |
|||
|
|||
/* Desktop styly (výchozí) */ |
|||
.col-6 { |
|||
width: 50%; |
|||
float: left; |
|||
} |
|||
|
|||
/* Tablet (do 768px) */ |
|||
@media (max-width: 768px) { |
|||
.col-6 { |
|||
width: 100%; |
|||
} |
|||
} |
|||
|
|||
/* Mobil (do 480px) */ |
|||
@media (max-width: 480px) { |
|||
.col-6 { |
|||
width: 100%; |
|||
} |
|||
body { |
|||
font-size: 14px; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Otevřete **Developer Tools** (F12) a zapněte **Device Toolbar** (Ctrl+Shift+M) |
|||
3. Změňte velikost okna nebo vyberte různá zařízení (iPhone, iPad, Desktop) |
|||
4. Sledujte, jak se mění layout při různých velikostech |
|||
5. Prozkoumejte `style.css` - najděte `@media` pravidla |
|||
6. Zkuste přidat vlastní breakpointy a změny stylů |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
- **VŽDY použijte viewport meta tag** - bez něj responzivita na mobilu nebude fungovat! |
|||
- **Breakpointy** (běžné hodnoty): |
|||
- Mobil: `max-width: 480px` |
|||
- Tablet: `max-width: 768px` |
|||
- Desktop: `min-width: 769px` nebo bez media query |
|||
- **Mobile-first** přístup (doporučený): |
|||
- Výchozí styly pro mobil |
|||
- Media queries s `min-width` pro větší obrazovky |
|||
- **Desktop-first** přístup: |
|||
- Výchozí styly pro desktop |
|||
- Media queries s `max-width` pro menší obrazovky |
|||
- Testujte na **reálných zařízeních**, ne jen v prohlížeči |
|||
|
|||
## 📱 Testování responzivity |
|||
|
|||
**V prohlížeči:** |
|||
1. F12 → Device Toolbar (Ctrl+Shift+M) |
|||
2. Vyberte zařízení nebo nastavte vlastní rozměry |
|||
3. Otočte zařízení (landscape/portrait) |
|||
|
|||
**Běžné rozlišení:** |
|||
- iPhone: 375px × 667px |
|||
- iPad: 768px × 1024px |
|||
- Desktop: 1920px × 1080px |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 08_js_form - JavaScript a formuláře |
|||
- **Další:** 10_flex - Flexbox layout |
|||
- **Související:** |
|||
- 12_grid - CSS Grid (další layout systém) |
|||
- AI/ai_01_grid_responsive - praktický projekt s responzivitou |
|||
@ -0,0 +1,129 @@ |
|||
# 10 - Flexbox Layout |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet moderní layouty pomocí CSS Flexbox. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Flexbox základy** - `display: flex` |
|||
- **Flex container** vlastnosti: |
|||
- `flex-direction` (row, column) |
|||
- `justify-content` (zarovnání na hlavní ose) |
|||
- `align-items` (zarovnání na vedlejší ose) |
|||
- `flex-wrap` (zalamování položek) |
|||
- `gap` (mezery mezi položkami) |
|||
- **Flex items** vlastnosti: |
|||
- `flex-grow`, `flex-shrink`, `flex-basis` |
|||
- `align-self` (individuální zarovnání) |
|||
- **Praktické použití** - navigace, karty, layout |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML struktura s flexbox layoutem |
|||
- `style.css` - CSS s flexbox vlastnostmi |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```css |
|||
/* Flex container */ |
|||
.wrapper { |
|||
display: flex; |
|||
flex-direction: row; |
|||
flex-wrap: wrap; |
|||
gap: 20px; |
|||
} |
|||
|
|||
/* Flex items */ |
|||
.main { |
|||
flex: 2; /* flex-grow: 2 */ |
|||
} |
|||
|
|||
.aside { |
|||
flex: 1; /* flex-grow: 1 */ |
|||
} |
|||
|
|||
/* Navigace s flexbox */ |
|||
.navigace { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Otevřete **Developer Tools** (F12) a vyberte flexbox element |
|||
3. V Chrome DevTools najdete **Flexbox** badge - klikněte pro vizualizaci |
|||
4. Prozkoumejte `style.css` - jak funguje `display: flex` |
|||
5. Zkuste měnit `flex-direction`, `justify-content`, `align-items` |
|||
6. Změňte velikost okna a sledujte, jak se flex items přizpůsobují |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Kdy použít Flexbox: |
|||
- ✅ Navigační menu (horizontální nebo vertikální) |
|||
- ✅ Karty/produkty vedle sebe |
|||
- ✅ Centrování elementů (horizontálně i vertikálně) |
|||
- ✅ Jednosměrné layouty (řádek nebo sloupec) |
|||
|
|||
### Kdy raději Grid: |
|||
- ❌ Komplexní dvourozměrné layouty (řádky + sloupce) |
|||
- ❌ Galerie obrázků |
|||
- ❌ Celostránkové layouty s header, sidebar, main, footer |
|||
|
|||
### Hlavní koncept: |
|||
- **Flex container** = rodič s `display: flex` |
|||
- **Flex items** = přímé potomci flex containeru |
|||
|
|||
### Důležité vlastnosti: |
|||
```css |
|||
/* Na kontejneru */ |
|||
display: flex; |
|||
justify-content: center; /* horizontální zarovnání */ |
|||
align-items: center; /* vertikální zarovnání */ |
|||
gap: 20px; /* mezery mezi položkami */ |
|||
|
|||
/* Na položkách */ |
|||
flex: 1; /* roztáhne položku */ |
|||
``` |
|||
|
|||
## 🎯 Praktické příklady |
|||
|
|||
**Centrování:** |
|||
```css |
|||
.container { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 100vh; |
|||
} |
|||
``` |
|||
|
|||
**Horizontální navigace:** |
|||
```css |
|||
nav { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
} |
|||
``` |
|||
|
|||
**Responzivní karty:** |
|||
```css |
|||
.card-container { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 20px; |
|||
} |
|||
.card { |
|||
flex: 1 1 300px; /* min šířka 300px */ |
|||
} |
|||
``` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 09_mediaquerry - responzivní design |
|||
- **Další:** 11_json - práce s JSON |
|||
- **Porovnání:** 12_grid - CSS Grid (dvourozměrný layout) |
|||
- **Praktický projekt:** AI/ai_04_prep_bootstrap - kombinace Flex a Grid |
|||
@ -0,0 +1,117 @@ |
|||
# 11 - JSON a Práce s Daty |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte pracovat s JSON formátem a načítat data do JavaScriptu. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **JSON formát** (JavaScript Object Notation) |
|||
- **JSON.parse()** - převod JSON stringu na objekt |
|||
- **JSON.stringify()** - převod objektu na JSON string |
|||
- **Načítání dat z JSON souborů** |
|||
- **Práce s JSON daty** v JavaScriptu |
|||
- **Výpis dat na stránku** pomocí DOM manipulace |
|||
- **Pole objektů** - procházení cyklem |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s elementy pro zobrazení dat |
|||
- `js/app.js` - JavaScript pro práce s JSON |
|||
- `data/` (možná) - složka s JSON soubory |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```javascript |
|||
// JSON objekt v JavaScriptu |
|||
const osoba = { |
|||
"jmeno": "Jan", |
|||
"prijmeni": "Novák", |
|||
"vek": 20, |
|||
"mesto": "Praha" |
|||
}; |
|||
|
|||
// Výpis dat |
|||
console.log(osoba.jmeno); // Jan |
|||
|
|||
// JSON string |
|||
const jsonString = '{"jmeno":"Jan","vek":20}'; |
|||
|
|||
// Převod stringu na objekt |
|||
const obj = JSON.parse(jsonString); |
|||
console.log(obj.jmeno); // Jan |
|||
|
|||
// Převod objektu na string |
|||
const str = JSON.stringify(osoba); |
|||
console.log(str); // {"jmeno":"Jan",...} |
|||
|
|||
// Pole objektů |
|||
const osoby = [ |
|||
{"jmeno": "Jan", "vek": 20}, |
|||
{"jmeno": "Petra", "vek": 25}, |
|||
{"jmeno": "Karel", "vek": 30} |
|||
]; |
|||
|
|||
// Procházení pole |
|||
osoby.forEach(function(osoba) { |
|||
console.log(osoba.jmeno + " má " + osoba.vek + " let"); |
|||
}); |
|||
|
|||
// Výpis na stránku |
|||
let html = ""; |
|||
osoby.forEach(function(osoba) { |
|||
html += "<p>" + osoba.jmeno + "</p>"; |
|||
}); |
|||
document.getElementById("demo").innerHTML = html; |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Otevřete **Console** (F12) a sledujte výpis JSON dat |
|||
3. Prozkoumejte `js/app.js` - jak se pracuje s JSON |
|||
4. Zkuste vytvořit vlastní JSON objekt |
|||
5. Vyzkoušejte převody mezi objektem a stringem |
|||
6. Vytvořte pole objektů a vypište je na stránku |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### JSON syntaxe: |
|||
- **Klíče musí být v uvozovkách**: `{"jmeno": "Jan"}` ✅ |
|||
- **Hodnoty**: string (v uvozovkách), číslo, boolean, null, objekt, pole |
|||
- **Čárka** mezi položkami, ale ne za poslední |
|||
- **Žádné komentáře** v JSON! |
|||
|
|||
### Běžné chyby: |
|||
```javascript |
|||
// ❌ ŠPATNĚ - klíče bez uvozovek |
|||
{jmeno: "Jan"} |
|||
|
|||
// ✅ SPRÁVNĚ |
|||
{"jmeno": "Jan"} |
|||
|
|||
// ❌ ŠPATNĚ - čárka za posledním |
|||
{"jmeno": "Jan", "vek": 20,} |
|||
|
|||
// ✅ SPRÁVNĚ |
|||
{"jmeno": "Jan", "vek": 20} |
|||
``` |
|||
|
|||
### JSON vs JavaScript objekt: |
|||
- **JSON** = textový formát (string), univerzální |
|||
- **JS objekt** = datová struktura v paměti |
|||
- **JSON.parse()** = převod z textu na objekt |
|||
- **JSON.stringify()** = převod z objektu na text |
|||
|
|||
### Praktické použití: |
|||
- 💾 Ukládání dat do localStorage |
|||
- 🌐 Komunikace s API (fetch) |
|||
- 📤 Odesílání dat na server |
|||
- 📥 Načítání konfigurace |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 10_flex - Flexbox layout |
|||
- **Další:** 12_grid - CSS Grid |
|||
- **Pokročilé:** 20_ajax - AJAX a Fetch API (načítání JSON ze serveru) |
|||
- **Praktické:** Práce s API a reálnými JSON daty |
|||
@ -0,0 +1,150 @@ |
|||
# 12 - CSS Grid Layout |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet komplexní dvourozměrné layouty pomocí CSS Grid. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **CSS Grid základy** - `display: grid` |
|||
- **Grid container** vlastnosti: |
|||
- `grid-template-columns` (definice sloupců) |
|||
- `grid-template-rows` (definice řádků) |
|||
- `gap`, `column-gap`, `row-gap` (mezery) |
|||
- `grid-template-areas` (pojmenované oblasti) |
|||
- **Grid items** vlastnosti: |
|||
- `grid-column`, `grid-row` (umístění položky) |
|||
- `grid-area` (pojmenovaná oblast) |
|||
- **Responzivní Grid** - kombinace s media queries |
|||
- **Galerie** - praktické použití Gridu |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s grid strukturou |
|||
- `style.css` - CSS s grid definicemi |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```css |
|||
/* Grid container - galerie */ |
|||
.grid-container { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); /* 3 stejně široké sloupce */ |
|||
gap: 20px; /* mezery mezi položkami */ |
|||
} |
|||
|
|||
/* Grid items */ |
|||
.grid-item { |
|||
background-color: lightblue; |
|||
padding: 20px; |
|||
} |
|||
|
|||
/* První položka zabere 2 sloupce */ |
|||
.grid-item:first-child { |
|||
grid-column: span 2; |
|||
} |
|||
|
|||
/* Responzivní Grid */ |
|||
@media (max-width: 768px) { |
|||
.grid-container { |
|||
grid-template-columns: repeat(2, 1fr); /* 2 sloupce na tabletu */ |
|||
} |
|||
} |
|||
|
|||
@media (max-width: 480px) { |
|||
.grid-container { |
|||
grid-template-columns: 1fr; /* 1 sloupec na mobilu */ |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Otevřete **Developer Tools** (F12) a vyberte grid element |
|||
3. V Chrome DevTools najdete **Grid** badge - klikněte pro vizualizaci mřížky |
|||
4. Prozkoumejte `style.css` - jak funguje `display: grid` |
|||
5. Zkuste měnit počet sloupců: `grid-template-columns: repeat(4, 1fr)` |
|||
6. Experimentujte s `gap`, `grid-column`, `grid-row` |
|||
7. Změňte velikost okna a sledujte responzivitu |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Kdy použít Grid: |
|||
- ✅ Komplexní dvourozměrné layouty (řádky + sloupce) |
|||
- ✅ Galerie obrázků |
|||
- ✅ Celostránkové layouty (header, sidebar, main, footer) |
|||
- ✅ Dashboardy, karty v mřížce |
|||
- ✅ Kalendáře |
|||
|
|||
### Kdy raději Flexbox: |
|||
- ❌ Jednosměrné layouty (jen řádek nebo jen sloupec) |
|||
- ❌ Navigační menu |
|||
- ❌ Jednoduchá centrování |
|||
|
|||
### Hlavní jednotky: |
|||
- **fr** (fraction) = podíl dostupného prostoru |
|||
- `1fr 2fr` = první sloupec 1/3, druhý 2/3 |
|||
- **px** = pevná velikost |
|||
- **%** = procenta z containeru |
|||
- **auto** = automatická velikost podle obsahu |
|||
|
|||
### Grid layout pattern: |
|||
```css |
|||
/* Kontejner */ |
|||
.grid-container { |
|||
display: grid; /* MUSÍ BÝT! */ |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 20px; |
|||
} |
|||
|
|||
/* Položky se umístí automaticky */ |
|||
.grid-item { |
|||
/* žádné speciální vlastnosti potřeba */ |
|||
} |
|||
``` |
|||
|
|||
## 🎯 Praktické příklady |
|||
|
|||
**Galerie 3 sloupce:** |
|||
```css |
|||
.galerie { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); |
|||
gap: 10px; |
|||
} |
|||
``` |
|||
|
|||
**Responzivní galerie (bez media queries!):** |
|||
```css |
|||
.galerie { |
|||
display: grid; |
|||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); |
|||
gap: 20px; |
|||
} |
|||
``` |
|||
|
|||
**Layout stránky:** |
|||
```css |
|||
.layout { |
|||
display: grid; |
|||
grid-template-columns: 250px 1fr; /* sidebar + main */ |
|||
grid-template-rows: 80px 1fr 60px; /* header + content + footer */ |
|||
gap: 10px; |
|||
height: 100vh; |
|||
} |
|||
``` |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
1. **display: grid musí být na KONTEJNERU**, ne na položkách! |
|||
2. **Grid položky** = pouze přímé děti grid containeru |
|||
3. Použijte **Chrome DevTools Grid inspector** pro debugování |
|||
4. **repeat()** funkce šetří psaní: `repeat(3, 1fr)` = `1fr 1fr 1fr` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 11_json - práce s JSON |
|||
- **Další:** 13_bootstrap_intro - úvod do Bootstrapu |
|||
- **Porovnání:** 10_flex - Flexbox (jednosměrný layout) |
|||
- **Praktický projekt:** AI/ai_01_grid_responsive - kompletní Grid projekt s responzivitou |
|||
@ -0,0 +1,119 @@ |
|||
# 13 - Úvod do Bootstrapu |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se seznámíte s Bootstrap frameworkem a jeho základními komponentami. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Co je Bootstrap** - CSS framework pro rychlý vývoj |
|||
- **Připojení Bootstrapu** k projektu (lokální soubory) |
|||
- **Container** - základní obal pro obsah (`.container`) |
|||
- **Grid systém** - 12sloupcová mřížka |
|||
- `.row` - řádek |
|||
- `.col` - sloupce (automatická šířka) |
|||
- `.col-6` - sloupec se šířkou 6/12 |
|||
- **Responzivní třídy** - `col-md-6`, `col-lg-3` |
|||
- **Typography** - `display-1`, `display-5` |
|||
- **Utility třídy**: |
|||
- Okraje: `m-2`, `mx-2`, `p-2` |
|||
- Borders: `border`, `border-danger`, `rounded` |
|||
- Další: `<mark>`, `<code>`, `<kbd>` |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s Bootstrap třídami |
|||
- `css/bootstrap.css` - Bootstrap CSS (lokální) |
|||
- `js/bootstrap.js` - Bootstrap JavaScript (lokální) |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```html |
|||
<!-- Container --> |
|||
<div class="container"> |
|||
<h1 class="display-1">Hello, Bootstrap!</h1> |
|||
|
|||
<!-- Grid systém --> |
|||
<div class="row"> |
|||
<div class="col-md-6 col-lg-3"> |
|||
<div class="border border-primary rounded m-2 p-2"> |
|||
Obsah sloupce |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6 col-lg-3"> |
|||
Další sloupec |
|||
</div> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Prozkoumejte Bootstrap třídy v HTML |
|||
3. Změňte velikost okna - sledujte responzivní chování |
|||
4. Vyzkoušejte Developer Tools (F12) - Device Toolbar |
|||
5. Experimentujte s různými utility třídami |
|||
6. Změňte `col-md-6` na `col-lg-4` a sledujte změny |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Bootstrap Grid System: |
|||
- **12 sloupců celkem** v každém řádku |
|||
- **col-6** = 6/12 = 50% šířky |
|||
- **col-4** = 4/12 = 33.33% šířky |
|||
- **col** = automatická šířka (rovnoměrně rozdělí prostor) |
|||
|
|||
### Responzivní breakpointy: |
|||
- **xs** (extra small) = < 576px (mobil) - není třeba psát, je výchozí |
|||
- **sm** (small) = ≥ 576px |
|||
- **md** (medium) = ≥ 768px (tablet) |
|||
- **lg** (large) = ≥ 992px (desktop) |
|||
- **xl** (extra large) = ≥ 1200px |
|||
|
|||
### Příklad responzivity: |
|||
```html |
|||
<div class="col-12 col-md-6 col-lg-3"> |
|||
<!-- Mobil: 100% šířky (12/12) --> |
|||
<!-- Tablet: 50% šířky (6/12) --> |
|||
<!-- Desktop: 25% šířky (3/12) --> |
|||
</div> |
|||
``` |
|||
|
|||
### Container vs Container-fluid: |
|||
- **container** = fixní šířka, centrovaný |
|||
- **container-fluid** = 100% šířky |
|||
|
|||
### Důležité: |
|||
- VŽDY používejte **row** pro řádky |
|||
- Sloupce (**col**) musí být uvnitř **row** |
|||
- Celkový součet sloupců by měl být **12** (nebo méně) |
|||
|
|||
## 🎨 Utility třídy: |
|||
|
|||
```html |
|||
<!-- Okraje (margin) --> |
|||
m-2 = margin všude |
|||
mx-2 = margin vlevo a vpravo |
|||
my-3 = margin nahoře a dole |
|||
mt-4 = margin nahoře |
|||
|
|||
<!-- Padding --> |
|||
p-2 = padding všude |
|||
px-3 = padding vlevo a vpravo |
|||
|
|||
<!-- Borders --> |
|||
border = přidá border |
|||
border-primary = modrý border |
|||
border-3 = tlustší border |
|||
rounded = zaoblené rohy |
|||
``` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 12_grid - CSS Grid (pochopení grid systému) |
|||
- **Důležité přípravné projekty:** |
|||
- AI/ai_01_grid_responsive - CSS Grid praxe |
|||
- AI/ai_04_prep_bootstrap - komplexní příprava |
|||
- **Další:** 14_bootstrap_layout - pokročilejší Bootstrap layouty |
|||
- **Související:** 15_bootstrap_components - Bootstrap komponenty |
|||
@ -0,0 +1,162 @@ |
|||
# 14 - Bootstrap Layout |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet kompletní layout stránky s pomocí Bootstrapu. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Header s navigací** - `nav`, `nav-pills`, `nav-item` |
|||
- **Flexbox utility třídy** - `d-flex`, `justify-content-center`, `align-items-center` |
|||
- **Main content** - hlavní obsah stránky |
|||
- **Jumbotron** - velká úvodní sekce (hero section) |
|||
- **Tabulky** - `table`, `table-hover`, `table-dark`, `table-info` |
|||
- **Footer** - patička stránky s `mt-auto` |
|||
- **Sticky footer** - přilepený footer (flexbox pattern) |
|||
- **Buttons** - `btn`, `btn-primary` |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - kompletní layout s header, main, footer |
|||
- `css/bootstrap.css` - Bootstrap CSS |
|||
- `js/bootstrap.js` - Bootstrap JS |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
```html |
|||
<body class="d-flex flex-column min-vh-100"> |
|||
<!-- Header --> |
|||
<header class="d-flex flex-wrap justify-content-center py-3 border-bottom"> |
|||
<a href="#" class="me-auto fs-4">Název Stránky</a> |
|||
<ul class="nav nav-pills"> |
|||
<li class="nav-item"> |
|||
<a href="#" class="nav-link active">Home</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a href="#" class="nav-link">About</a> |
|||
</li> |
|||
</ul> |
|||
</header> |
|||
|
|||
<!-- Main --> |
|||
<main class="container"> |
|||
<!-- Jumbotron --> |
|||
<div class="p-5 bg-secondary text-white rounded"> |
|||
<h1 class="display-3">Hello world!</h1> |
|||
<p>Lorem ipsum...</p> |
|||
<a href="#" class="btn btn-primary">Více info</a> |
|||
</div> |
|||
|
|||
<!-- Tabulka --> |
|||
<table class="table table-hover"> |
|||
<tr class="table-dark"> |
|||
<td>Jméno</td> |
|||
<td>Email</td> |
|||
</tr> |
|||
<tr class="table-info"> |
|||
<td>Jan</td> |
|||
<td>jan@email.cz</td> |
|||
</tr> |
|||
</table> |
|||
</main> |
|||
|
|||
<!-- Footer --> |
|||
<footer class="footer mt-auto"> |
|||
<div class="nav justify-content-center py-2"> |
|||
<span>© 2025</span> |
|||
</div> |
|||
</footer> |
|||
</body> |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Prozkoumejte strukturu: header → main → footer |
|||
3. Změňte velikost okna - sledujte responzivní navigaci |
|||
4. Vyzkoušejte hover efekt na tabulce |
|||
5. Experimentujte s barevnými třídami tabulek |
|||
6. Zkuste přidat další navigační položky |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Sticky Footer pattern: |
|||
```html |
|||
<body class="d-flex flex-column min-vh-100"> |
|||
<header>...</header> |
|||
<main class="container">...</main> |
|||
<footer class="footer mt-auto">...</footer> |
|||
</body> |
|||
``` |
|||
- **d-flex flex-column** = flexbox ve vertikálním směru |
|||
- **min-vh-100** = minimální výška 100% viewportu |
|||
- **mt-auto** = margin-top: auto (footer se přilepí dolů) |
|||
|
|||
### Flexbox utility třídy: |
|||
```html |
|||
<!-- Display --> |
|||
d-flex = display: flex |
|||
d-inline-flex = display: inline-flex |
|||
|
|||
<!-- Direction --> |
|||
flex-row = řádkový (výchozí) |
|||
flex-column = sloupcový |
|||
|
|||
<!-- Justify content (horizontální zarovnání) --> |
|||
justify-content-start = vlevo |
|||
justify-content-center = na střed |
|||
justify-content-end = vpravo |
|||
justify-content-between = mezi |
|||
|
|||
<!-- Align items (vertikální zarovnání) --> |
|||
align-items-start = nahoře |
|||
align-items-center = na střed |
|||
align-items-end = dole |
|||
``` |
|||
|
|||
### Navigace: |
|||
```html |
|||
<ul class="nav nav-pills"> |
|||
<li class="nav-item"> |
|||
<a href="#" class="nav-link active">Aktivní odkaz</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a href="#" class="nav-link disabled">Neaktivní odkaz</a> |
|||
</li> |
|||
</ul> |
|||
``` |
|||
|
|||
### Tabulky: |
|||
```html |
|||
<!-- Základní tabulka --> |
|||
<table class="table">...</table> |
|||
|
|||
<!-- S hover efektem --> |
|||
<table class="table table-hover">...</table> |
|||
|
|||
<!-- Barevné řádky --> |
|||
<tr class="table-primary">...</tr> <!-- modrá --> |
|||
<tr class="table-success">...</tr> <!-- zelená --> |
|||
<tr class="table-danger">...</tr> <!-- červená --> |
|||
<tr class="table-warning">...</tr> <!-- žlutá --> |
|||
<tr class="table-info">...</tr> <!-- světle modrá --> |
|||
<tr class="table-dark">...</tr> <!-- tmavá --> |
|||
``` |
|||
|
|||
### Buttons: |
|||
```html |
|||
<button class="btn btn-primary">Primary</button> |
|||
<button class="btn btn-secondary">Secondary</button> |
|||
<button class="btn btn-success">Success</button> |
|||
<button class="btn btn-danger">Danger</button> |
|||
<button class="btn btn-warning">Warning</button> |
|||
<button class="btn btn-outline-primary">Outline</button> |
|||
``` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 13_bootstrap_intro - úvod do Bootstrapu |
|||
- **Další:** 15_bootstrap_components - Bootstrap komponenty |
|||
- **Související:** |
|||
- 10_flex - Flexbox (pochopení flexbox utility tříd) |
|||
- AI/ai_02_semantic_portfolio - sémantická struktura stránky |
|||
@ -0,0 +1,165 @@ |
|||
# 15 - Bootstrap Komponenty |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte používat základní Bootstrap komponenty pro vytváření interaktivních webů. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Cards** - kartičky pro obsah |
|||
- **Buttons** - tlačítka různých stylů |
|||
- **Badges** - odznaky pro zvýraznění |
|||
- **Alerts** - upozornění a zprávy |
|||
- **Progress bars** - indikátory průběhu |
|||
- **Breadcrumbs** - navigační drobečková navigace |
|||
- **Pagination** - stránkování |
|||
- **List groups** - stylované seznamy |
|||
- **Forms** - formulářové komponenty |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - ukázky Bootstrap komponent |
|||
- `css/bootstrap.css` - Bootstrap CSS |
|||
- `js/bootstrap.js` - Bootstrap JS |
|||
|
|||
## 💻 Ukázky komponent |
|||
|
|||
### Cards (Kartičky) |
|||
```html |
|||
<div class="card" style="width: 18rem;"> |
|||
<img src="..." class="card-img-top" alt="..."> |
|||
<div class="card-body"> |
|||
<h5 class="card-title">Nadpis karty</h5> |
|||
<p class="card-text">Text karty...</p> |
|||
<a href="#" class="btn btn-primary">Tlačítko</a> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
### Alerts |
|||
```html |
|||
<div class="alert alert-primary" role="alert"> |
|||
Primární alert |
|||
</div> |
|||
<div class="alert alert-success" role="alert"> |
|||
Úspěšná operace! |
|||
</div> |
|||
<div class="alert alert-danger" role="alert"> |
|||
Chyba! |
|||
</div> |
|||
``` |
|||
|
|||
### Badges |
|||
```html |
|||
<h1>Nadpis <span class="badge bg-secondary">Nový</span></h1> |
|||
<button class="btn btn-primary"> |
|||
Notifikace <span class="badge bg-danger">4</span> |
|||
</button> |
|||
``` |
|||
|
|||
### Progress Bar |
|||
```html |
|||
<div class="progress"> |
|||
<div class="progress-bar" role="progressbar" |
|||
style="width: 75%" aria-valuenow="75" |
|||
aria-valuemin="0" aria-valuemax="100">75%</div> |
|||
</div> |
|||
|
|||
<!-- Barevné --> |
|||
<div class="progress"> |
|||
<div class="progress-bar bg-success" style="width: 50%">50%</div> |
|||
</div> |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Prozkoumejte různé komponenty |
|||
3. Vyzkoušejte změnit barvy komponent (primary → success) |
|||
4. Experimentujte s kombinacemi komponent |
|||
5. Zkuste vytvořit vlastní kartu s obrázkem a tlačítkem |
|||
6. Prozkoumejte Bootstrap dokumentaci pro více variant |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Card layout: |
|||
```html |
|||
<!-- Grid s kartami --> |
|||
<div class="row"> |
|||
<div class="col-md-4"> |
|||
<div class="card"> |
|||
<div class="card-body"> |
|||
<h5 class="card-title">Karta 1</h5> |
|||
<p class="card-text">Obsah...</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="card">...</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="card">...</div> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
### Bootstrap barvy (color variants): |
|||
Většina komponent podporuje barevné varianty: |
|||
- **primary** = modrá (hlavní) |
|||
- **secondary** = šedá |
|||
- **success** = zelená (úspěch) |
|||
- **danger** = červená (chyba) |
|||
- **warning** = žlutá (varování) |
|||
- **info** = světle modrá (info) |
|||
- **light** = světlá |
|||
- **dark** = tmavá |
|||
|
|||
### List Groups: |
|||
```html |
|||
<ul class="list-group"> |
|||
<li class="list-group-item">První položka</li> |
|||
<li class="list-group-item active">Aktivní položka</li> |
|||
<li class="list-group-item">Třetí položka</li> |
|||
</ul> |
|||
``` |
|||
|
|||
### Breadcrumbs: |
|||
```html |
|||
<nav aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"><a href="#">Home</a></li> |
|||
<li class="breadcrumb-item"><a href="#">Produkty</a></li> |
|||
<li class="breadcrumb-item active">Notebook</li> |
|||
</ol> |
|||
</nav> |
|||
``` |
|||
|
|||
### Pagination: |
|||
```html |
|||
<nav> |
|||
<ul class="pagination"> |
|||
<li class="page-item"><a class="page-link" href="#">Předchozí</a></li> |
|||
<li class="page-item"><a class="page-link" href="#">1</a></li> |
|||
<li class="page-item active"><a class="page-link" href="#">2</a></li> |
|||
<li class="page-item"><a class="page-link" href="#">3</a></li> |
|||
<li class="page-item"><a class="page-link" href="#">Další</a></li> |
|||
</ul> |
|||
</nav> |
|||
``` |
|||
|
|||
## 🎨 Praktické využití |
|||
|
|||
**E-shop produkty** = Cards |
|||
**Úspěšné odeslání formuláře** = Alert success |
|||
**Počet položek v košíku** = Badge |
|||
**Upload souboru** = Progress bar |
|||
**Navigace kategoriemi** = Breadcrumbs |
|||
**Seznam článků** = Pagination |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 14_bootstrap_layout - Bootstrap layout |
|||
- **Další:** |
|||
- 16_carousel - Bootstrap carousel (slider) |
|||
- 17_modal - Bootstrap modal (okna) |
|||
- **Dokumentace:** [Bootstrap Components](https://getbootstrap.com/docs/5.3/components/) |
|||
@ -0,0 +1,171 @@ |
|||
# 16 - Bootstrap Carousel |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet carousel (slider/slideshow) pomocí Bootstrapu. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Carousel** - posuvný slider obrázků |
|||
- **Carousel indicators** - indikátory snímků (tečky) |
|||
- **Carousel controls** - ovládací šipky |
|||
- **Carousel captions** - popisky k obrázkům |
|||
- **Auto-sliding** - automatické přepínání |
|||
- **JavaScript carousel API** - ovládání přes JS |
|||
- **Data attributes** - `data-bs-ride`, `data-bs-slide-to` |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s carousel komponentou |
|||
- `css/bootstrap.css` - Bootstrap CSS |
|||
- `js/bootstrap.js` - Bootstrap JS (DŮLEŽITÝ pro carousel!) |
|||
- `images/` - obrázky pro carousel |
|||
|
|||
## 💻 Základní Carousel |
|||
|
|||
```html |
|||
<div id="carouselExample" class="carousel slide" data-bs-ride="carousel"> |
|||
<!-- Indikátory (tečky) --> |
|||
<div class="carousel-indicators"> |
|||
<button type="button" data-bs-target="#carouselExample" |
|||
data-bs-slide-to="0" class="active"></button> |
|||
<button type="button" data-bs-target="#carouselExample" |
|||
data-bs-slide-to="1"></button> |
|||
<button type="button" data-bs-target="#carouselExample" |
|||
data-bs-slide-to="2"></button> |
|||
</div> |
|||
|
|||
<!-- Snímky --> |
|||
<div class="carousel-inner"> |
|||
<div class="carousel-item active"> |
|||
<img src="slide1.jpg" class="d-block w-100" alt="Slide 1"> |
|||
<div class="carousel-caption"> |
|||
<h5>První snímek</h5> |
|||
<p>Popis prvního snímku</p> |
|||
</div> |
|||
</div> |
|||
<div class="carousel-item"> |
|||
<img src="slide2.jpg" class="d-block w-100" alt="Slide 2"> |
|||
</div> |
|||
<div class="carousel-item"> |
|||
<img src="slide3.jpg" class="d-block w-100" alt="Slide 3"> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Ovládací šipky --> |
|||
<button class="carousel-control-prev" type="button" |
|||
data-bs-target="#carouselExample" data-bs-slide="prev"> |
|||
<span class="carousel-control-prev-icon"></span> |
|||
</button> |
|||
<button class="carousel-control-next" type="button" |
|||
data-bs-target="#carouselExample" data-bs-slide="next"> |
|||
<span class="carousel-control-next-icon"></span> |
|||
</button> |
|||
</div> |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Sledujte automatické přepínání snímků |
|||
3. Vyzkoušejte kliknout na šipky (prev/next) |
|||
4. Klikněte na indikátory (tečky) pro přímý přechod |
|||
5. Prozkoumejte HTML - všimněte si `data-bs-*` atributů |
|||
6. Zkuste přidat další snímek (carousel-item) |
|||
7. Změňte caption texty |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Důležité třídy: |
|||
- **carousel slide** - hlavní wrapper |
|||
- **carousel-inner** - kontejner pro snímky |
|||
- **carousel-item** - jednotlivý snímek |
|||
- **carousel-item active** - aktivní (viditelný) snímek |
|||
- **d-block w-100** - obrázek na celou šířku |
|||
|
|||
### Data attributes: |
|||
```html |
|||
<!-- Automatické spuštění --> |
|||
data-bs-ride="carousel" |
|||
|
|||
<!-- Přechod na konkrétní snímek --> |
|||
data-bs-slide-to="0" <!-- první snímek (indexováno od 0) --> |
|||
|
|||
<!-- Přechod vpřed/vzad --> |
|||
data-bs-slide="prev" <!-- předchozí --> |
|||
data-bs-slide="next" <!-- další --> |
|||
|
|||
<!-- Interval mezi snímky (v ms) --> |
|||
data-bs-interval="5000" <!-- 5 sekund --> |
|||
``` |
|||
|
|||
### Carousel varianty: |
|||
|
|||
**Bez automatického přepínání:** |
|||
```html |
|||
<div class="carousel slide"> <!-- bez data-bs-ride --> |
|||
``` |
|||
|
|||
**Fade efekt místo slide:** |
|||
```html |
|||
<div class="carousel slide carousel-fade" data-bs-ride="carousel"> |
|||
``` |
|||
|
|||
**Vlastní interval:** |
|||
```html |
|||
<div class="carousel-item" data-bs-interval="2000"> |
|||
<!-- tento snímek se zobrazí 2 sekundy --> |
|||
</div> |
|||
``` |
|||
|
|||
### JavaScript API: |
|||
|
|||
```javascript |
|||
// Získání carousel instance |
|||
var myCarousel = document.querySelector('#myCarousel') |
|||
var carousel = new bootstrap.Carousel(myCarousel) |
|||
|
|||
// Ovládání |
|||
carousel.next() // další snímek |
|||
carousel.prev() // předchozí snímek |
|||
carousel.to(2) // přechod na snímek 2 |
|||
carousel.cycle() // spustit automatické přepínání |
|||
carousel.pause() // pozastavit |
|||
``` |
|||
|
|||
### Responzivní carousel: |
|||
```html |
|||
<!-- Různé výšky pro různá zařízení --> |
|||
<style> |
|||
.carousel-item img { |
|||
height: 400px; |
|||
object-fit: cover; |
|||
} |
|||
|
|||
@media (max-width: 768px) { |
|||
.carousel-item img { |
|||
height: 250px; |
|||
} |
|||
} |
|||
</style> |
|||
``` |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
1. **První carousel-item musí mít třídu `active`** |
|||
2. **Všechny data-bs-target musí odpovídat ID carouselu** |
|||
3. **Bootstrap.js musí být připojen** - carousel funguje na JavaScriptu |
|||
4. **Obrázky by měly mít stejné rozměry** pro hezký vzhled |
|||
|
|||
## 🎯 Praktické využití |
|||
|
|||
- **Hlavní stránka** - hero slider s produkty |
|||
- **Galerie** - slideshow fotek |
|||
- **Testimonials** - recenze zákazníků |
|||
- **Portfolio** - ukázky projektů |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 15_bootstrap_components - Bootstrap komponenty |
|||
- **Další:** 17_modal - Bootstrap modal |
|||
- **Dokumentace:** [Bootstrap Carousel](https://getbootstrap.com/docs/5.3/components/carousel/) |
|||
@ -0,0 +1,224 @@ |
|||
# 17 - Bootstrap Modal |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet modální okna (pop-up okna) pomocí Bootstrapu. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Modal** - modální okno (overlay) |
|||
- **Modal struktura** - header, body, footer |
|||
- **Data attributes** - `data-bs-toggle`, `data-bs-target` |
|||
- **Modal velikosti** - malé, velké, extra velké |
|||
- **Scrollable modal** - pro dlouhý obsah |
|||
- **Centered modal** - centrované na obrazovce |
|||
- **JavaScript Modal API** - otevírání/zavírání přes JS |
|||
- **Modal events** - události (show, hide) |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s modal komponentou |
|||
- `css/bootstrap.css` - Bootstrap CSS |
|||
- `js/bootstrap.js` - Bootstrap JS (DŮLEŽITÝ pro modal!) |
|||
|
|||
## 💻 Základní Modal |
|||
|
|||
```html |
|||
<!-- Tlačítko pro otevření modalu --> |
|||
<button type="button" class="btn btn-primary" |
|||
data-bs-toggle="modal" data-bs-target="#exampleModal"> |
|||
Otevřít modal |
|||
</button> |
|||
|
|||
<!-- Modal struktura --> |
|||
<div class="modal fade" id="exampleModal" tabindex="-1"> |
|||
<div class="modal-dialog"> |
|||
<div class="modal-content"> |
|||
<!-- Header --> |
|||
<div class="modal-header"> |
|||
<h5 class="modal-title">Nadpis modalu</h5> |
|||
<button type="button" class="btn-close" |
|||
data-bs-dismiss="modal"></button> |
|||
</div> |
|||
|
|||
<!-- Body --> |
|||
<div class="modal-body"> |
|||
<p>Obsah modálního okna...</p> |
|||
</div> |
|||
|
|||
<!-- Footer --> |
|||
<div class="modal-footer"> |
|||
<button type="button" class="btn btn-secondary" |
|||
data-bs-dismiss="modal">Zavřít</button> |
|||
<button type="button" class="btn btn-primary">Uložit</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Klikněte na tlačítko pro otevření modalu |
|||
3. Vyzkoušejte zavření pomocí: |
|||
- Křížku (×) |
|||
- Tlačítka "Zavřít" |
|||
- Kliknutí mimo modal |
|||
- Klávesy Esc |
|||
4. Prozkoumejte HTML strukturu modalu |
|||
5. Zkuste změnit velikost modalu |
|||
6. Přidejte formulář do modal-body |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Data attributes: |
|||
|
|||
**Otevření modalu:** |
|||
```html |
|||
<button data-bs-toggle="modal" data-bs-target="#myModal"> |
|||
Otevřít |
|||
</button> |
|||
``` |
|||
- **data-bs-toggle="modal"** - zapne modal funkcionalitu |
|||
- **data-bs-target="#myModal"** - ID modalu, který se otevře |
|||
|
|||
**Zavření modalu:** |
|||
```html |
|||
<button data-bs-dismiss="modal">Zavřít</button> |
|||
``` |
|||
|
|||
### Velikosti modalu: |
|||
|
|||
```html |
|||
<!-- Malý modal --> |
|||
<div class="modal-dialog modal-sm"> |
|||
|
|||
<!-- Normální (výchozí) --> |
|||
<div class="modal-dialog"> |
|||
|
|||
<!-- Velký --> |
|||
<div class="modal-dialog modal-lg"> |
|||
|
|||
<!-- Extra velký --> |
|||
<div class="modal-dialog modal-xl"> |
|||
|
|||
<!-- Celá obrazovka --> |
|||
<div class="modal-dialog modal-fullscreen"> |
|||
``` |
|||
|
|||
### Centrovaný modal: |
|||
|
|||
```html |
|||
<div class="modal-dialog modal-dialog-centered"> |
|||
<!-- vertikálně centrovaný --> |
|||
</div> |
|||
``` |
|||
|
|||
### Scrollable modal (dlouhý obsah): |
|||
|
|||
```html |
|||
<div class="modal-dialog modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
<div class="modal-body"> |
|||
<!-- dlouhý obsah zde --> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
### JavaScript API: |
|||
|
|||
```javascript |
|||
// Otevření modalu přes JavaScript |
|||
var myModal = new bootstrap.Modal(document.getElementById('myModal')) |
|||
myModal.show() |
|||
|
|||
// Zavření |
|||
myModal.hide() |
|||
|
|||
// Přepnutí (toggle) |
|||
myModal.toggle() |
|||
``` |
|||
|
|||
### Modal events: |
|||
|
|||
```javascript |
|||
var modalEl = document.getElementById('myModal') |
|||
|
|||
// Před otevřením |
|||
modalEl.addEventListener('show.bs.modal', function () { |
|||
console.log('Modal se otevírá') |
|||
}) |
|||
|
|||
// Po otevření |
|||
modalEl.addEventListener('shown.bs.modal', function () { |
|||
console.log('Modal je otevřený') |
|||
}) |
|||
|
|||
// Před zavřením |
|||
modalEl.addEventListener('hide.bs.modal', function () { |
|||
console.log('Modal se zavírá') |
|||
}) |
|||
|
|||
// Po zavření |
|||
modalEl.addEventListener('hidden.bs.modal', function () { |
|||
console.log('Modal je zavřený') |
|||
}) |
|||
``` |
|||
|
|||
## 🎯 Praktické příklady |
|||
|
|||
### Modal s formulářem: |
|||
|
|||
```html |
|||
<div class="modal-body"> |
|||
<form> |
|||
<div class="mb-3"> |
|||
<label for="email" class="form-label">Email</label> |
|||
<input type="email" class="form-control" id="email"> |
|||
</div> |
|||
<div class="mb-3"> |
|||
<label for="password" class="form-label">Heslo</label> |
|||
<input type="password" class="form-control" id="password"> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
``` |
|||
|
|||
### Potvrzovací dialog: |
|||
|
|||
```html |
|||
<div class="modal-body"> |
|||
<p>Opravdu chcete smazat tento záznam?</p> |
|||
</div> |
|||
<div class="modal-footer"> |
|||
<button class="btn btn-secondary" data-bs-dismiss="modal">Ne</button> |
|||
<button class="btn btn-danger" onclick="deleteRecord()">Ano, smazat</button> |
|||
</div> |
|||
``` |
|||
|
|||
## 🎨 Praktické využití |
|||
|
|||
- **Přihlášení/Registrace** - formulář v modalu |
|||
- **Potvrzení akce** - "Opravdu smazat?" |
|||
- **Detaily produktu** - zobrazení více informací |
|||
- **Galerie obrázků** - lightbox efekt |
|||
- **Video přehrávač** - YouTube/Vimeo embed |
|||
- **Notifikace** - důležité zprávy |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
1. **Modal musí mít jedinečné ID** |
|||
2. **Bootstrap.js musí být připojen** - modal funguje na JavaScriptu |
|||
3. **data-bs-target musí odpovídat ID modalu** |
|||
4. **Vnořené modaly se nedoporučují** (modal v modalu) |
|||
5. **Backdrop** (tmavé pozadí) se dá vypnout: `data-bs-backdrop="false"` |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 16_carousel - Bootstrap carousel |
|||
- **Související:** |
|||
- 15_bootstrap_components - ostatní komponenty |
|||
- AI/ai_04_prep_bootstrap - vlastní modal implementace |
|||
- **Dokumentace:** [Bootstrap Modal](https://getbootstrap.com/docs/5.3/components/modal/) |
|||
@ -0,0 +1,181 @@ |
|||
# 18 - Bootstrap Formuláře a DOM Manipulace |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvářet dynamické formuláře s Bootstrapem a DOM manipulací. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Bootstrap formuláře** - `form-control`, `form-label`, `mb-3` |
|||
- **addEventListener** - moderní přístup k event handlingu |
|||
- **event.preventDefault()** - zabránění default chování formuláře |
|||
- **DOM manipulace** - vytváření elementů pomocí JS |
|||
- **createElement()** - vytvoření nového elementu |
|||
- **appendChild()** - přidání elementu do DOM |
|||
- **Template literals** - backticks pro HTML šablony |
|||
- **Bootstrap Cards** - kartičky pro obsah |
|||
- **Real-time výpis** - návštěvní kniha |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - kompletní aplikace s formulářem a výpisem |
|||
- `css/bootstrap.css` - Bootstrap CSS |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
### Formulář s Bootstrap třídami: |
|||
```html |
|||
<form id="guestbookForm"> |
|||
<div class="mb-3"> |
|||
<label for="name" class="form-label">Jméno:</label> |
|||
<input type="text" class="form-control" id="name" required> |
|||
</div> |
|||
<div class="mb-3"> |
|||
<label for="message" class="form-label">Zpráva:</label> |
|||
<textarea class="form-control" id="message" required></textarea> |
|||
</div> |
|||
<button type="submit" class="btn btn-danger w-100">ODESLAT</button> |
|||
</form> |
|||
|
|||
<div id="entries"></div> |
|||
``` |
|||
|
|||
### JavaScript - Template Literals (rychlejší): |
|||
```javascript |
|||
form.addEventListener("submit", function(e) { |
|||
e.preventDefault(); |
|||
|
|||
const name = document.getElementById("name").value; |
|||
const message = document.getElementById("message").value; |
|||
|
|||
// Template literal s backticks |
|||
const htmldiv = ` |
|||
<div class="alert alert-info"> |
|||
<strong>${name}</strong>: ${message} |
|||
</div> |
|||
`; |
|||
|
|||
entriesDiv.innerHTML += htmldiv; |
|||
form.reset(); |
|||
}); |
|||
``` |
|||
|
|||
### JavaScript - createElement (strukturovanější): |
|||
```javascript |
|||
form.addEventListener("submit", function(e) { |
|||
e.preventDefault(); |
|||
|
|||
const name = document.getElementById("name").value; |
|||
const message = document.getElementById("message").value; |
|||
|
|||
// Vytvoření elementů |
|||
const div = document.createElement("div"); |
|||
div.className = "alert alert-danger"; |
|||
|
|||
const strong = document.createElement("strong"); |
|||
strong.textContent = name; |
|||
|
|||
const text = document.createElement("span"); |
|||
text.textContent = ": " + message; |
|||
|
|||
// Složení dohromady |
|||
div.appendChild(strong); |
|||
div.appendChild(text); |
|||
|
|||
// Vložení do stránky |
|||
entriesDiv.appendChild(div); |
|||
|
|||
form.reset(); |
|||
}); |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Vyplňte jméno a zprávu do formuláře |
|||
3. Odešlete formulář - zpráva se objeví pod formulářem |
|||
4. Přidejte další zprávy - všechny se zobrazí |
|||
5. Prozkoumejte JavaScript kód - dvě různé metody |
|||
6. Vyzkoušejte Developer Tools (F12) - sledujte DOM změny |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### addEventListener vs onclick: |
|||
```javascript |
|||
// ✅ MODERNÍ přístup (doporučený) |
|||
form.addEventListener("submit", function(e) { |
|||
e.preventDefault(); |
|||
// ... |
|||
}); |
|||
|
|||
// ❌ STARŠÍ přístup (méně flexibilní) |
|||
<form onsubmit="return handleSubmit()"> |
|||
``` |
|||
|
|||
### event.preventDefault(): |
|||
```javascript |
|||
form.addEventListener("submit", function(e) { |
|||
e.preventDefault(); // Zastaví odeslání a reload stránky |
|||
// Můžeme zpracovat data vlastním způsobem |
|||
}); |
|||
``` |
|||
|
|||
### Template Literals (backticks): |
|||
```javascript |
|||
// Starý způsob (konkatenace) |
|||
const html = "<div>" + name + ": " + message + "</div>"; |
|||
|
|||
// ✅ Nový způsob (template literal) |
|||
const html = `<div>${name}: ${message}</div>`; |
|||
``` |
|||
- Používá **backticks** (AltGr + ý) |
|||
- **${proměnná}** - vložení hodnoty proměnné |
|||
- Podporuje **víceřádkové stringy** |
|||
|
|||
### innerHTML vs appendChild: |
|||
|
|||
**innerHTML** - rychlé, ale přepisuje vše: |
|||
```javascript |
|||
div.innerHTML = `<p>Nový obsah</p>`; |
|||
div.innerHTML += `<p>Přidaný obsah</p>`; |
|||
``` |
|||
|
|||
**appendChild** - přidává element, lepší pro DOM manipulaci: |
|||
```javascript |
|||
const p = document.createElement("p"); |
|||
p.textContent = "Nový obsah"; |
|||
div.appendChild(p); |
|||
``` |
|||
|
|||
### Bootstrap Form Classes: |
|||
```html |
|||
<!-- Form group --> |
|||
<div class="mb-3"> <!-- margin-bottom: 1rem --> |
|||
<label class="form-label">Název</label> |
|||
<input class="form-control" type="text"> |
|||
</div> |
|||
|
|||
<!-- Input velikosti --> |
|||
<input class="form-control form-control-sm"> <!-- malý --> |
|||
<input class="form-control"> <!-- normální --> |
|||
<input class="form-control form-control-lg"> <!-- velký --> |
|||
|
|||
<!-- Full width button --> |
|||
<button class="btn btn-primary w-100">Tlačítko</button> |
|||
``` |
|||
|
|||
## 🎯 Praktické využití |
|||
|
|||
- **Návštěvní kniha** - uživatelé zanechávají vzkazy |
|||
- **Chat aplikace** - zprávy v real-time |
|||
- **Komentáře** - pod článkem |
|||
- **Todo list** - přidávání úkolů |
|||
- **Košík** - přidávání produktů |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** |
|||
- 17_modal - Bootstrap modal |
|||
- 08_js_form - základy formulářů v JS |
|||
- **Další:** 19_todolist - Todo list aplikace |
|||
- **Související:** AI/ai_03_form_validation - pokročilá validace formulářů |
|||
@ -0,0 +1,220 @@ |
|||
# 19 - Todo List Aplikace |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte vytvořit kompletní Todo List aplikaci s přidáváním, odebíráním a označováním úkolů. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **Todo List aplikace** - praktický projekt |
|||
- **Dynamické přidávání položek** do seznamu |
|||
- **Odstranění položek** z DOM |
|||
- **Toggle stavu** - splněno/nesplněno |
|||
- **Local Storage** - ukládání dat v prohlížeči (možná) |
|||
- **Event delegation** - efektivní event handling |
|||
- **Bootstrap styling** pro moderní UI |
|||
- **Textarea** - víceřádkový vstup |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - HTML s formulářem a seznamem |
|||
- `todo.js` - JavaScript pro funkcionalitu |
|||
- `css/bootstrap.css` - Bootstrap CSS |
|||
|
|||
## 💻 Ukázka z lekce |
|||
|
|||
### HTML struktura: |
|||
```html |
|||
<textarea class="form-control velkytext" id="todoitem" |
|||
placeholder="Zde napiš úkol"></textarea> |
|||
<button class="btn btn-primary w-100 my-3" onclick="additem()"> |
|||
ZAPSAT |
|||
</button> |
|||
|
|||
<ul id="todoList"></ul> |
|||
``` |
|||
|
|||
### JavaScript - Přidání úkolu: |
|||
```javascript |
|||
function additem() { |
|||
const todoitem = document.getElementById("todoitem").value; |
|||
|
|||
if (todoitem === "") { |
|||
alert("Zadej úkol!"); |
|||
return; |
|||
} |
|||
|
|||
const todoList = document.getElementById("todoList"); |
|||
|
|||
// Vytvoření <li> elementu |
|||
const li = document.createElement("li"); |
|||
li.className = "todolistitem"; |
|||
li.innerHTML = ` |
|||
${todoitem} |
|||
<button class="btn btn-danger btn-sm ms-2" |
|||
onclick="removeitem(this)">Smazat</button> |
|||
<button class="btn btn-success btn-sm ms-1" |
|||
onclick="toggleitem(this)">Hotovo</button> |
|||
`; |
|||
|
|||
todoList.appendChild(li); |
|||
|
|||
// Vyčištění textarea |
|||
document.getElementById("todoitem").value = ""; |
|||
} |
|||
|
|||
// Odstranění úkolu |
|||
function removeitem(button) { |
|||
const li = button.parentElement; |
|||
li.remove(); |
|||
} |
|||
|
|||
// Toggle splněno/nesplněno |
|||
function toggleitem(button) { |
|||
const li = button.parentElement; |
|||
li.classList.toggle("text-decoration-line-through"); |
|||
li.classList.toggle("text-muted"); |
|||
} |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Napište úkol do textarey |
|||
3. Klikněte na "ZAPSAT" - úkol se přidá do seznamu |
|||
4. Vyzkoušejte tlačítko "Hotovo" - přeškrtne úkol |
|||
5. Klikněte na "Smazat" - odstraní úkol ze seznamu |
|||
6. Přidejte více úkolů a vyzkoušejte všechny funkce |
|||
7. Prozkoumejte `todo.js` - jak funguje logika |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### parentElement: |
|||
```javascript |
|||
function removeitem(button) { |
|||
// button = <button> element |
|||
// button.parentElement = <li> element (rodič) |
|||
const li = button.parentElement; |
|||
li.remove(); |
|||
} |
|||
``` |
|||
|
|||
### classList.toggle(): |
|||
```javascript |
|||
// Toggle třídy (přidá/odebere) |
|||
element.classList.toggle("active"); |
|||
|
|||
// Přidá třídu |
|||
element.classList.add("active"); |
|||
|
|||
// Odebere třídu |
|||
element.classList.remove("active"); |
|||
|
|||
// Zkontroluje, zda má třídu |
|||
element.classList.contains("active"); // true/false |
|||
``` |
|||
|
|||
### text-decoration-line-through: |
|||
```html |
|||
<!-- Přeškrtnutý text --> |
|||
<p class="text-decoration-line-through">Dokončeno</p> |
|||
``` |
|||
|
|||
### Validace vstupu: |
|||
```javascript |
|||
if (todoitem === "" || todoitem.trim() === "") { |
|||
alert("Zadej úkol!"); |
|||
return; // Ukončí funkci |
|||
} |
|||
``` |
|||
|
|||
## 🎯 Rozšíření projektu |
|||
|
|||
### 1. Local Storage (ukládání dat): |
|||
```javascript |
|||
// Uložení do local storage |
|||
function saveTodos() { |
|||
const todos = []; |
|||
document.querySelectorAll("#todoList li").forEach(li => { |
|||
todos.push(li.textContent); |
|||
}); |
|||
localStorage.setItem("todos", JSON.stringify(todos)); |
|||
} |
|||
|
|||
// Načtení z local storage |
|||
function loadTodos() { |
|||
const todos = JSON.parse(localStorage.getItem("todos")) || []; |
|||
todos.forEach(todo => { |
|||
// Přidat do seznamu |
|||
}); |
|||
} |
|||
|
|||
// Volat při načtení stránky |
|||
window.onload = loadTodos; |
|||
``` |
|||
|
|||
### 2. Počítadlo úkolů: |
|||
```html |
|||
<p>Celkem úkolů: <span id="totalCount">0</span></p> |
|||
<p>Dokončeno: <span id="completedCount">0</span></p> |
|||
``` |
|||
|
|||
```javascript |
|||
function updateCounters() { |
|||
const total = document.querySelectorAll("#todoList li").length; |
|||
const completed = document.querySelectorAll("#todoList li.text-decoration-line-through").length; |
|||
|
|||
document.getElementById("totalCount").textContent = total; |
|||
document.getElementById("completedCount").textContent = completed; |
|||
} |
|||
``` |
|||
|
|||
### 3. Priorita úkolů: |
|||
```html |
|||
<select id="priority" class="form-select"> |
|||
<option value="low">Nízká</option> |
|||
<option value="medium">Střední</option> |
|||
<option value="high">Vysoká</option> |
|||
</select> |
|||
``` |
|||
|
|||
```javascript |
|||
// Barevné označení podle priority |
|||
if (priority === "high") { |
|||
li.classList.add("border-start", "border-danger", "border-5"); |
|||
} |
|||
``` |
|||
|
|||
### 4. Editace úkolů: |
|||
```javascript |
|||
function edititem(button) { |
|||
const li = button.parentElement; |
|||
const newText = prompt("Upravit úkol:", li.firstChild.textContent); |
|||
if (newText) { |
|||
// Aktualizovat text úkolu |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
1. **Validace vstupu** - kontrolujte prázdné hodnoty |
|||
2. **trim()** - odstraní mezery na začátku a konci |
|||
3. **this** v onclick - odkazuje na button element |
|||
4. **remove()** - moderní způsob odstranění elementu |
|||
|
|||
## 🎨 Praktické využití |
|||
|
|||
- **Todo List** - osobní úkoly |
|||
- **Nákupní seznam** - položky k nákupu |
|||
- **Checklist** - kontrolní seznam |
|||
- **Poznámky** - rychlé poznámky |
|||
- **Cíle** - tracking cílů |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** 18_forms - formuláře a DOM manipulace |
|||
- **Další:** 20_ajax - AJAX a Fetch API |
|||
- **Související:** |
|||
- 11_json - práce s JSON (pro localStorage) |
|||
- 06_js_html - základy DOM manipulace |
|||
@ -0,0 +1,228 @@ |
|||
# 20 - AJAX a Fetch API |
|||
|
|||
## 🎯 Co se naučíte |
|||
|
|||
V této lekci se naučíte načítat data z externích API pomocí Fetch API. |
|||
|
|||
## 📚 Témata lekce |
|||
|
|||
- **AJAX** - Asynchronous JavaScript and XML |
|||
- **Fetch API** - moderní způsob načítání dat |
|||
- **Promises** - asynchronní operace |
|||
- **async/await** - čistší syntax pro asynchronní kód |
|||
- **JSON API** - práce s REST API |
|||
- **Pokémon API** - praktická ukázka (pokeapi.co) |
|||
- **JSONPlaceholder** - testovací API (jsonplaceholder.typicode.com) |
|||
- **Error handling** - ošetření chyb při načítání |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - rozcestník |
|||
- `pokemon.html` - práce s Pokémon API |
|||
- `todofetch.html` - práce s Todo API |
|||
- JavaScript soubory pro fetch operace |
|||
|
|||
## 💻 Základní Fetch |
|||
|
|||
### Fetch - Promise syntax: |
|||
```javascript |
|||
// Načtení dat z API |
|||
fetch('https://pokeapi.co/api/v2/pokemon/pikachu') |
|||
.then(response => response.json()) // Převod na JSON |
|||
.then(data => { |
|||
console.log(data); |
|||
// Práce s daty |
|||
document.getElementById("name").textContent = data.name; |
|||
}) |
|||
.catch(error => { |
|||
console.error('Chyba:', error); |
|||
alert('Nepodařilo se načíst data'); |
|||
}); |
|||
``` |
|||
|
|||
### Fetch - async/await syntax (modernější): |
|||
```javascript |
|||
async function loadPokemon() { |
|||
try { |
|||
const response = await fetch('https://pokeapi.co/api/v2/pokemon/pikachu'); |
|||
const data = await response.json(); |
|||
|
|||
console.log(data); |
|||
document.getElementById("name").textContent = data.name; |
|||
document.getElementById("image").src = data.sprites.front_default; |
|||
|
|||
} catch (error) { |
|||
console.error('Chyba:', error); |
|||
alert('Nepodařilo se načíst data'); |
|||
} |
|||
} |
|||
|
|||
// Volání funkce |
|||
loadPokemon(); |
|||
``` |
|||
|
|||
## 🚀 Jak s lekcí pracovat |
|||
|
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Klikněte na "Práce s Pokémon API" |
|||
3. Sledujte načítání dat z API |
|||
4. Otevřete **Console** (F12) - uvidíte API odpovědi |
|||
5. Vyzkoušejte "Práce s TodoList API" |
|||
6. Prozkoumejte JavaScript kód - jak funguje fetch |
|||
7. Zkuste změnit URL API a načíst jiná data |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
### Fetch API kroky: |
|||
|
|||
1. **Zavolat fetch()** s URL |
|||
2. **Počkat na response** (.then nebo await) |
|||
3. **Převést na JSON** (.json()) |
|||
4. **Použít data** (zobrazit, zpracovat) |
|||
5. **Ošetřit chyby** (.catch nebo try/catch) |
|||
|
|||
### GET request (načtení dat): |
|||
```javascript |
|||
fetch('https://api.example.com/data') |
|||
.then(response => response.json()) |
|||
.then(data => console.log(data)) |
|||
.catch(error => console.error(error)); |
|||
``` |
|||
|
|||
### POST request (odeslání dat): |
|||
```javascript |
|||
fetch('https://api.example.com/data', { |
|||
method: 'POST', |
|||
headers: { |
|||
'Content-Type': 'application/json' |
|||
}, |
|||
body: JSON.stringify({ |
|||
title: 'Nový úkol', |
|||
completed: false |
|||
}) |
|||
}) |
|||
.then(response => response.json()) |
|||
.then(data => console.log('Vytvořeno:', data)) |
|||
.catch(error => console.error('Chyba:', error)); |
|||
``` |
|||
|
|||
### Async/Await pattern: |
|||
```javascript |
|||
async function getData() { |
|||
try { |
|||
const response = await fetch(url); |
|||
|
|||
// Kontrola, zda je response OK |
|||
if (!response.ok) { |
|||
throw new Error('Network response was not ok'); |
|||
} |
|||
|
|||
const data = await response.json(); |
|||
return data; |
|||
|
|||
} catch (error) { |
|||
console.error('Error:', error); |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
// Použití |
|||
getData() |
|||
.then(data => console.log(data)) |
|||
.catch(error => console.error(error)); |
|||
``` |
|||
|
|||
### Loading indicator: |
|||
```javascript |
|||
async function loadData() { |
|||
// Zobrazit loading |
|||
document.getElementById("loading").style.display = "block"; |
|||
|
|||
try { |
|||
const response = await fetch(url); |
|||
const data = await response.json(); |
|||
|
|||
// Zpracovat data |
|||
displayData(data); |
|||
|
|||
} catch (error) { |
|||
console.error(error); |
|||
} finally { |
|||
// Skrýt loading |
|||
document.getElementById("loading").style.display = "none"; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## 🎯 Praktické příklady |
|||
|
|||
### Pokémon API: |
|||
```javascript |
|||
async function loadPokemon(name) { |
|||
const url = `https://pokeapi.co/api/v2/pokemon/${name}`; |
|||
|
|||
const response = await fetch(url); |
|||
const pokemon = await response.json(); |
|||
|
|||
// Zobrazení dat |
|||
document.getElementById("pokemonName").textContent = pokemon.name; |
|||
document.getElementById("pokemonImage").src = pokemon.sprites.front_default; |
|||
document.getElementById("pokemonType").textContent = pokemon.types[0].type.name; |
|||
document.getElementById("pokemonWeight").textContent = pokemon.weight; |
|||
} |
|||
|
|||
// Volání |
|||
loadPokemon("pikachu"); |
|||
``` |
|||
|
|||
### JSONPlaceholder - Todo API: |
|||
```javascript |
|||
async function loadTodos() { |
|||
const response = await fetch('https://jsonplaceholder.typicode.com/todos'); |
|||
const todos = await response.json(); |
|||
|
|||
// Zobrazit prvních 10 todos |
|||
const ul = document.getElementById("todoList"); |
|||
todos.slice(0, 10).forEach(todo => { |
|||
const li = document.createElement("li"); |
|||
li.className = todo.completed ? "completed" : ""; |
|||
li.textContent = todo.title; |
|||
ul.appendChild(li); |
|||
}); |
|||
} |
|||
``` |
|||
|
|||
## 🌐 Užitečná testovací API |
|||
|
|||
- **JSONPlaceholder**: https://jsonplaceholder.typicode.com/ |
|||
- Fake REST API pro testování |
|||
- Todos, posts, users, comments |
|||
|
|||
- **PokeAPI**: https://pokeapi.co/ |
|||
- Pokémon data |
|||
- Obrázky, statistiky, typy |
|||
|
|||
- **OpenWeather API**: https://openweathermap.org/api |
|||
- Počasí (vyžaduje API klíč) |
|||
|
|||
- **Cat Facts API**: https://catfact.ninja/fact |
|||
- Náhodné fakty o kočkách |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
1. **CORS** - některá API mohou blokovat requesty z prohlížeče |
|||
2. **API klíče** - některá API vyžadují registraci a klíč |
|||
3. **Rate limiting** - omezení počtu requestů |
|||
4. **async funkce** vrací vždy Promise |
|||
5. **await** lze použít pouze v async funkci |
|||
6. **try/catch** vždy použijte pro error handling |
|||
|
|||
## 🔗 Související lekce |
|||
|
|||
- **Předchozí:** |
|||
- 19_todolist - Todo list aplikace |
|||
- 11_json - práce s JSON |
|||
- **Související:** API integrace v reálných projektech |
|||
- **Dokumentace:** |
|||
- [Fetch API - MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) |
|||
- [Async/Await - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) |
|||
@ -0,0 +1,248 @@ |
|||
# Lekce 18: Bootstrap Formuláře a Validace |
|||
|
|||
## 🎯 Cíl lekce |
|||
|
|||
Naučit studenty pracovat s Bootstrap formuláři a validací. **Studenti se s validací formulářů setkávají poprvé!** |
|||
|
|||
## 📝 Osnova lekce |
|||
|
|||
### Část 1: Základní Bootstrap formuláře (20 min) |
|||
- Třída `form-control` pro input, textarea |
|||
- Třída `form-select` pro select |
|||
- Třída `form-check-input` pro checkbox/radio |
|||
- `form-label` pro popisky |
|||
- `form-text` pro nápovědu |
|||
- Spacing pomocí `mb-3` (margin-bottom) |
|||
|
|||
### Část 2: HTML5 validace (15 min) |
|||
- Atribut `required` - povinné pole |
|||
- `minlength` a `maxlength` - omezení délky |
|||
- `min` a `max` pro number input |
|||
- `pattern` - regulární výrazy pro formát |
|||
- `type="email"`, `type="tel"`, `type="number"` |
|||
|
|||
### Část 3: Bootstrap validační styly (20 min) |
|||
- Třídy `is-valid` a `is-invalid` |
|||
- `valid-feedback` - zelená zpráva ✅ |
|||
- `invalid-feedback` - červená zpráva ❌ |
|||
- Třída `needs-validation` na formuláři |
|||
- JavaScript validace s `checkValidity()` |
|||
- Třída `was-validated` pro zobrazení feedbacku |
|||
|
|||
### Část 4: Input Groups (10 min) |
|||
- `input-group` pro seskupení |
|||
- `input-group-text` pro prefix/suffix |
|||
- Praktické použití: @ před emailem, +420 před tel., Kč za cenou |
|||
|
|||
### Část 5: Floating Labels (10 min) |
|||
- Moderní vzhled formulářů |
|||
- `form-floating` wrapper |
|||
- Label se "vyplaví" nahoru při focusu |
|||
|
|||
### Část 6: Praktický projekt (40 min) |
|||
Studenti vytvoří vlastní kontaktní formulář |
|||
|
|||
## 📁 Soubory v této lekci |
|||
|
|||
### `index.html` |
|||
Hlavní soubor s 5 demo sekcemi: |
|||
1. ✅ Základní formulář |
|||
2. ✅ HTML5 validace |
|||
3. ✅ Bootstrap validace s JavaScriptem |
|||
4. ✅ Input Groups |
|||
5. ✅ Floating Labels |
|||
|
|||
**Použití:** Projděte s studenty všechny sekce postupně. Nechte je vyzkoušet formuláře! |
|||
|
|||
### `template.html` |
|||
Startovací šablona pro studenty s: |
|||
- ✅ Základní HTML strukturou |
|||
- ✅ Jedním ukázkovým polem |
|||
- ✅ Připraveným JavaScriptem |
|||
- ✅ Nápovědou v sidebaru |
|||
|
|||
**Použití:** Studenti mohou tuto šablonu použít jako základ pro svůj projekt. |
|||
|
|||
### `reseni_kontaktni_formular.html` |
|||
Kompletní řešení projektu obsahující: |
|||
- ✅ Všechna požadovaná pole |
|||
- ✅ Floating labels |
|||
- ✅ Input group u telefonu (+420) |
|||
- ✅ Validaci všech polí |
|||
- ✅ Success alert po odeslání |
|||
- ✅ BONUS funkce: |
|||
- Real-time validace telefonu |
|||
- Počítadlo znaků u zprávy |
|||
- Scroll k chybám |
|||
- Console.log výpis dat |
|||
|
|||
**Použití:** Ukažte studentům po dokončení jejich projektů. Projděte zejména JavaScript část! |
|||
|
|||
## 🎯 Projekt pro studenty |
|||
|
|||
### Zadání: Kontaktní formulář |
|||
|
|||
Vytvořte plně funkční kontaktní formulář s těmito požadavky: |
|||
|
|||
#### Povinná pole: |
|||
1. **Jméno** - textový input, required |
|||
2. **Email** - emailový input, required, správný formát |
|||
3. **Předmět** - select s možnostmi, required |
|||
4. **Zpráva** - textarea, required, min. 10 znaků |
|||
|
|||
#### Nepovinné pole: |
|||
5. **Telefon** - tel input s pattern `[0-9]{9}` (české číslo) |
|||
|
|||
#### Další požadavky: |
|||
- ✅ Checkbox "Souhlasím se zpracováním údajů" (required) |
|||
- ✅ Použít **Floating labels** pro všechna pole |
|||
- ✅ **Input group** u telefonu s textem "+420" |
|||
- ✅ Zobrazit **Success Alert** po úspěšném odeslání |
|||
- ✅ Validovat pomocí JavaScriptu |
|||
- ✅ Resetovat formulář po 3-4 sekundách |
|||
|
|||
#### Bonus úkoly: |
|||
- Real-time validace během psaní |
|||
- Počítadlo znaků u zprávy |
|||
- Scroll k prvnímu chybnému poli |
|||
- Vypsat data do console.log |
|||
|
|||
### Hodnocení (20 bodů): |
|||
|
|||
- **HTML struktura (5b)** |
|||
- Správná struktura formuláře (2b) |
|||
- Všechna pole implementována (2b) |
|||
- Správné atributy (required, pattern, type) (1b) |
|||
|
|||
- **Bootstrap styly (5b)** |
|||
- Floating labels použity správně (2b) |
|||
- Input group u telefonu (1b) |
|||
- Správné Bootstrap třídy (form-control, atd.) (2b) |
|||
|
|||
- **Validace (6b)** |
|||
- HTML5 validace správně nastavena (2b) |
|||
- JavaScript validace funguje (3b) |
|||
- Invalid/valid feedback zprávy (1b) |
|||
|
|||
- **Funkčnost (4b)** |
|||
- Formulář se validuje před odesláním (2b) |
|||
- Success alert se zobrazí (1b) |
|||
- Formulář se resetuje (1b) |
|||
|
|||
**Bonusové body (+5b max):** |
|||
- Real-time validace (+2b) |
|||
- Počítadlo znaků (+1b) |
|||
- Scroll k chybám (+1b) |
|||
- Console.log výpis (+1b) |
|||
|
|||
## 💡 Tipy pro učitele |
|||
|
|||
### Při výuce: |
|||
|
|||
1. **Začněte prakticky** - Nechte studenty rovnou zkoušet formuláře v `index.html` |
|||
|
|||
2. **Vysvětlete rozdíl** mezi: |
|||
- HTML5 validací (vestavěná v prohlížeči) |
|||
- Bootstrap validací (vizuální feedback) |
|||
- JavaScript validací (programová kontrola) |
|||
|
|||
3. **Ukažte DevTools** - Zapněte Console a ukazujte jak funguje `checkValidity()` |
|||
|
|||
4. **Pattern (RegEx)** - Nebojte se! Ukažte jen jednoduché příklady: |
|||
- `[0-9]{9}` = přesně 9 číslic |
|||
- `[0-9]{5}` = PSČ (5 číslic) |
|||
- Odkažte na regex101.com pro testování |
|||
|
|||
5. **Event preventDefault** - Vysvětlete proč musíme zastavit defaultní submit |
|||
|
|||
### Časté chyby studentů: |
|||
|
|||
❌ **Zapomenou `novalidate` na formuláři** |
|||
- Výsledek: Prohlížeč zobrazí vlastní validaci místo Bootstrap stylů |
|||
- Řešení: `<form class="needs-validation" novalidate>` |
|||
|
|||
❌ **Zapomenou `event.preventDefault()`** |
|||
- Výsledek: Formulář se odešle a stránka se obnoví |
|||
- Řešení: První řádek v event listeneru musí být `event.preventDefault()` |
|||
|
|||
❌ **Nepoužijí `was-validated` třídu** |
|||
- Výsledek: Feedback zprávy se nezobrazí |
|||
- Řešení: Po submitu přidat `form.classList.add('was-validated')` |
|||
|
|||
❌ **Dají `is-valid` přímo do HTML** |
|||
- Výsledek: Pole vypadá validní už před vyplněním |
|||
- Řešení: Třídy `is-valid`/`is-invalid` se přidávají JavaScriptem, ne v HTML |
|||
|
|||
❌ **Špatný selector pro feedback** |
|||
- Výsledek: Zprávy se nezobrazí u správného pole |
|||
- Řešení: `invalid-feedback` musí být sourozenec inputu (na stejné úrovni) |
|||
|
|||
## 📊 Postup výuky (90 min) |
|||
|
|||
### Fáze 1: Představení (10 min) |
|||
- Ukažte hotový `reseni_kontaktni_formular.html` |
|||
- Vyplňte správně i špatně - ukažte rozdíl |
|||
- Motivujte studenty: "Tohle dnes vytvoříte!" |
|||
|
|||
### Fáze 2: Průchod příklady (30 min) |
|||
- Otevřete `index.html` |
|||
- Projděte sekci po sekci |
|||
- Nechte studenty zkoušet každou sekci |
|||
- Vysvětlete JavaScript část u sekce 3 |
|||
|
|||
### Fáze 3: Template a zadání (10 min) |
|||
- Ukažte `template.html` |
|||
- Projděte zadání z `index.html` (sekce "Projekt pro vás") |
|||
- Zodpovězte dotazy |
|||
|
|||
### Fáze 4: Samostatná práce (35 min) |
|||
- Studenti pracují na projektu |
|||
- Procházejte mezi nimi |
|||
- Pomáhejte s dotazy |
|||
|
|||
### Fáze 5: Prezentace řešení (5 min) |
|||
- Otevřete `reseni_kontaktni_formular.html` |
|||
- Projděte kód |
|||
- Ukažte bonus funkce |
|||
|
|||
## 🔗 Navazující lekce |
|||
|
|||
Po této lekci můžete pokračovat: |
|||
- **19 - Alerts & Toasts** (notifikace uživateli) |
|||
- **20 - Navbar & Dropdowns** (navigace) |
|||
- **Závěrečný projekt** kombinující formuláře s jinými komponenty |
|||
|
|||
## 📚 Užitečné odkazy pro studenty |
|||
|
|||
- [Bootstrap Forms dokumentace](https://getbootstrap.com/docs/5.3/forms/overview/) |
|||
- [Bootstrap Validation](https://getbootstrap.com/docs/5.3/forms/validation/) |
|||
- [HTML5 Input types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) |
|||
- [RegEx tester](https://regex101.com/) |
|||
|
|||
## ✅ Co by studenti měli umět po této lekci |
|||
|
|||
Po absolvování lekce by studenti měli být schopni: |
|||
|
|||
✅ Vytvořit Bootstrap formulář se správnými třídami |
|||
✅ Použít HTML5 validační atributy (required, pattern, minlength) |
|||
✅ Implementovat JavaScript validaci pomocí `checkValidity()` |
|||
✅ Zobrazit validační feedback (zelený/červený) |
|||
✅ Vytvořit Input Groups s prefix/suffix |
|||
✅ Použít Floating Labels |
|||
✅ Zastavit defaultní odeslání formuláře |
|||
✅ Zobrazit Alert po úspěšném odeslání |
|||
✅ Resetovat formulář po odeslání |
|||
|
|||
**Bonusové dovednosti:** |
|||
- Real-time validace |
|||
- Počítadlo znaků |
|||
- Scroll k chybám |
|||
- Práce s console.log |
|||
|
|||
--- |
|||
|
|||
Vytvořeno: 2. prosince 2025 |
|||
Předmět: Webové Technologie (WTL) |
|||
Cílová skupina: 3. ročník IT |
|||
|
|||
**Hodně štěstí při výuce! 🚀** |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -0,0 +1,429 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Bootstrap Forms & Validace</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
<style> |
|||
.demo-section { |
|||
margin: 40px 0; |
|||
padding: 30px; |
|||
border: 2px solid #dee2e6; |
|||
border-radius: 10px; |
|||
background-color: #f8f9fa; |
|||
} |
|||
.demo-title { |
|||
color: #0d6efd; |
|||
margin-bottom: 20px; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body class="d-flex flex-column min-vh-100"> |
|||
<!-- Header --> |
|||
<div class="container"> |
|||
<header class="d-flex flex-wrap justify-content-center py-3 mb-3 border-bottom"> |
|||
<a href="#" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none fs-4"> |
|||
Bootstrap Forms & Validace |
|||
</a> |
|||
<ul class="nav nav-pills"> |
|||
<li class="nav-item"><a href="#zaklad" class="nav-link">Základy</a></li> |
|||
<li class="nav-item"><a href="#html-validace" class="nav-link">HTML validace</a></li> |
|||
<li class="nav-item"><a href="#bootstrap-validace" class="nav-link">Bootstrap validace</a></li> |
|||
<li class="nav-item"><a href="#projekt" class="nav-link active">Projekt</a></li> |
|||
</ul> |
|||
</header> |
|||
</div> |
|||
|
|||
<!-- MAIN --> |
|||
<main class="container"> |
|||
<h1 class="display-4 mb-4">Lekce 18: Formuláře a Validace</h1> |
|||
|
|||
<!-- SEKCE 1: Základní formulář --> |
|||
<div class="demo-section" id="zaklad"> |
|||
<h2 class="demo-title">1️⃣ Základní Bootstrap Formulář</h2> |
|||
<p class="lead">Bootstrap poskytuje krásné styly pro formuláře pomocí třídy <code>form-control</code></p> |
|||
|
|||
<form> |
|||
<!-- Textový input --> |
|||
<div class="mb-3"> |
|||
<label for="jmeno" class="form-label">Jméno:</label> |
|||
<input type="text" class="form-control" id="jmeno" placeholder="Zadejte jméno"> |
|||
</div> |
|||
|
|||
<!-- Email input --> |
|||
<div class="mb-3"> |
|||
<label for="email" class="form-label">Email:</label> |
|||
<input type="email" class="form-control" id="email" placeholder="vas@email.cz"> |
|||
<div class="form-text">Zadejte platnou emailovou adresu</div> |
|||
</div> |
|||
|
|||
<!-- Password --> |
|||
<div class="mb-3"> |
|||
<label for="heslo" class="form-label">Heslo:</label> |
|||
<input type="password" class="form-control" id="heslo"> |
|||
</div> |
|||
|
|||
<!-- Textarea --> |
|||
<div class="mb-3"> |
|||
<label for="zprava" class="form-label">Zpráva:</label> |
|||
<textarea class="form-control" id="zprava" rows="3"></textarea> |
|||
</div> |
|||
|
|||
<!-- Select --> |
|||
<div class="mb-3"> |
|||
<label for="zeme" class="form-label">Země:</label> |
|||
<select class="form-select" id="zeme"> |
|||
<option selected>Vyberte zemi...</option> |
|||
<option value="cz">Česká republika</option> |
|||
<option value="sk">Slovensko</option> |
|||
<option value="pl">Polsko</option> |
|||
</select> |
|||
</div> |
|||
|
|||
<!-- Checkbox --> |
|||
<div class="mb-3 form-check"> |
|||
<input type="checkbox" class="form-check-input" id="souhlas"> |
|||
<label class="form-check-label" for="souhlas"> |
|||
Souhlasím s podmínkami |
|||
</label> |
|||
</div> |
|||
|
|||
<button type="submit" class="btn btn-primary">Odeslat</button> |
|||
</form> |
|||
</div> |
|||
|
|||
<!-- SEKCE 2: HTML5 validace --> |
|||
<div class="demo-section" id="html-validace"> |
|||
<h2 class="demo-title">2️⃣ HTML5 Validace (zabudovaná v prohlížeči)</h2> |
|||
<p class="lead">Pomocí HTML atributů <code>required</code>, <code>minlength</code>, <code>maxlength</code>, <code>pattern</code></p> |
|||
|
|||
<div class="alert alert-info"> |
|||
<strong>💡 Tip:</strong> Zkuste odeslat formulář bez vyplnění - prohlížeč vás upozorní! |
|||
</div> |
|||
|
|||
<form> |
|||
<!-- Required pole --> |
|||
<div class="mb-3"> |
|||
<label for="jmeno2" class="form-label">Jméno (povinné):</label> |
|||
<input type="text" class="form-control" id="jmeno2" required> |
|||
</div> |
|||
|
|||
<!-- Email s required --> |
|||
<div class="mb-3"> |
|||
<label for="email2" class="form-label">Email (povinný):</label> |
|||
<input type="email" class="form-control" id="email2" required> |
|||
</div> |
|||
|
|||
<!-- Min a max length --> |
|||
<div class="mb-3"> |
|||
<label for="username" class="form-label">Uživatelské jméno (min 3, max 15 znaků):</label> |
|||
<input type="text" class="form-control" id="username" |
|||
minlength="3" maxlength="15" required> |
|||
</div> |
|||
|
|||
<!-- Pattern (regulární výraz) --> |
|||
<div class="mb-3"> |
|||
<label for="telefon" class="form-label">Telefon (formát: 123456789):</label> |
|||
<input type="tel" class="form-control" id="telefon" |
|||
pattern="[0-9]{9}" |
|||
placeholder="123456789" |
|||
required> |
|||
</div> |
|||
|
|||
<!-- Number s min/max --> |
|||
<div class="mb-3"> |
|||
<label for="vek" class="form-label">Věk (15-120):</label> |
|||
<input type="number" class="form-control" id="vek" |
|||
min="15" max="120" required> |
|||
</div> |
|||
|
|||
<button type="submit" class="btn btn-success">Odeslat formulář</button> |
|||
</form> |
|||
</div> |
|||
|
|||
<!-- SEKCE 3: Bootstrap validace s vizuálním feedbackem --> |
|||
<div class="demo-section" id="bootstrap-validace"> |
|||
<h2 class="demo-title">3️⃣ Bootstrap Validace (s vizuálním feedbackem)</h2> |
|||
<p class="lead">Bootstrap třídy: <code>is-valid</code> (zelená), <code>is-invalid</code> (červená)</p> |
|||
|
|||
<!-- Příklad: správně vyplněné pole --> |
|||
<h4>✅ Správně vyplněné pole:</h4> |
|||
<div class="mb-3"> |
|||
<label for="validEmail" class="form-label">Email:</label> |
|||
<input type="email" class="form-control is-valid" id="validEmail" value="uzivatel@email.cz"> |
|||
<div class="valid-feedback"> |
|||
Vypadá to dobře! |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Příklad: špatně vyplněné pole --> |
|||
<h4>❌ Špatně vyplněné pole:</h4> |
|||
<div class="mb-3"> |
|||
<label for="invalidEmail" class="form-label">Email:</label> |
|||
<input type="email" class="form-control is-invalid" id="invalidEmail" value="spatnyemail"> |
|||
<div class="invalid-feedback"> |
|||
Zadejte prosím platnou emailovou adresu! |
|||
</div> |
|||
</div> |
|||
|
|||
<hr class="my-5"> |
|||
|
|||
<!-- Komplexní formulář s Bootstrap validací --> |
|||
<h3>📝 Kompletní registrační formulář s validací</h3> |
|||
<div class="alert alert-warning"> |
|||
<strong>⚠️ Pozor:</strong> Tento formulář používá JavaScript pro validaci. Klikněte na "Registrovat" a uvidíte validaci v akci! |
|||
</div> |
|||
|
|||
<form id="registrationForm" class="needs-validation" novalidate> |
|||
<div class="row"> |
|||
<div class="col-md-6 mb-3"> |
|||
<label for="regJmeno" class="form-label">Jméno *</label> |
|||
<input type="text" class="form-control" id="regJmeno" required> |
|||
<div class="invalid-feedback"> |
|||
Vyplňte prosím jméno. |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6 mb-3"> |
|||
<label for="regPrijmeni" class="form-label">Příjmení *</label> |
|||
<input type="text" class="form-control" id="regPrijmeni" required> |
|||
<div class="invalid-feedback"> |
|||
Vyplňte prosím příjmení. |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="regEmail" class="form-label">Email *</label> |
|||
<input type="email" class="form-control" id="regEmail" required> |
|||
<div class="invalid-feedback"> |
|||
Zadejte platnou emailovou adresu. |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="regUsername" class="form-label">Uživatelské jméno *</label> |
|||
<input type="text" class="form-control" id="regUsername" |
|||
minlength="3" maxlength="15" required> |
|||
<div class="invalid-feedback"> |
|||
Uživatelské jméno musí mít 3-15 znaků. |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="regHeslo" class="form-label">Heslo *</label> |
|||
<input type="password" class="form-control" id="regHeslo" |
|||
minlength="6" required> |
|||
<div class="invalid-feedback"> |
|||
Heslo musí mít alespoň 6 znaků. |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="regHeslo2" class="form-label">Heslo znovu *</label> |
|||
<input type="password" class="form-control" id="regHeslo2" required> |
|||
<div class="invalid-feedback"> |
|||
Hesla se musí shodovat. |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="regVek" class="form-label">Věk *</label> |
|||
<input type="number" class="form-control" id="regVek" |
|||
min="15" max="120" required> |
|||
<div class="invalid-feedback"> |
|||
Věk musí být mezi 15 a 120 lety. |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="regZeme" class="form-label">Země *</label> |
|||
<select class="form-select" id="regZeme" required> |
|||
<option value="">Vyberte...</option> |
|||
<option value="cz">Česká republika</option> |
|||
<option value="sk">Slovensko</option> |
|||
<option value="pl">Polsko</option> |
|||
<option value="at">Rakousko</option> |
|||
</select> |
|||
<div class="invalid-feedback"> |
|||
Vyberte prosím zemi. |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3 form-check"> |
|||
<input type="checkbox" class="form-check-input" id="regSouhlas" required> |
|||
<label class="form-check-label" for="regSouhlas"> |
|||
Souhlasím s podmínkami * |
|||
</label> |
|||
<div class="invalid-feedback"> |
|||
Musíte souhlasit s podmínkami. |
|||
</div> |
|||
</div> |
|||
|
|||
<button type="submit" class="btn btn-primary btn-lg">Registrovat</button> |
|||
</form> |
|||
|
|||
<div id="successMessage" class="alert alert-success mt-4" style="display: none;"> |
|||
<h4>✅ Registrace úspěšná!</h4> |
|||
<p>Všechna pole byla vyplněna správně.</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- SEKCE 4: Input Groups --> |
|||
<div class="demo-section"> |
|||
<h2 class="demo-title">4️⃣ Input Groups (pole s ikonami/textem)</h2> |
|||
<p class="lead">Přidání textu nebo symbolů před/za input pole</p> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="username3" class="form-label">Uživatelské jméno:</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-text">@</span> |
|||
<input type="text" class="form-control" id="username3" placeholder="uzivatel"> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="website" class="form-label">Webová stránka:</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-text">https://</span> |
|||
<input type="text" class="form-control" id="website" placeholder="www.example.com"> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="cena" class="form-label">Cena:</label> |
|||
<div class="input-group"> |
|||
<input type="number" class="form-control" id="cena" placeholder="0"> |
|||
<span class="input-group-text">Kč</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="search" class="form-label">Vyhledávání:</label> |
|||
<div class="input-group"> |
|||
<input type="text" class="form-control" id="search" placeholder="Hledat..."> |
|||
<button class="btn btn-outline-secondary" type="button">🔍</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- SEKCE 5: Floating Labels --> |
|||
<div class="demo-section"> |
|||
<h2 class="demo-title">5️⃣ Floating Labels (moderní vzhled)</h2> |
|||
<p class="lead">Label se zobrazí uvnitř inputu a "vyplave" nahoru po kliknutí</p> |
|||
|
|||
<div class="form-floating mb-3"> |
|||
<input type="text" class="form-control" id="floatingJmeno" placeholder="Jméno"> |
|||
<label for="floatingJmeno">Jméno</label> |
|||
</div> |
|||
|
|||
<div class="form-floating mb-3"> |
|||
<input type="email" class="form-control" id="floatingEmail" placeholder="name@example.com"> |
|||
<label for="floatingEmail">Email</label> |
|||
</div> |
|||
|
|||
<div class="form-floating mb-3"> |
|||
<select class="form-select" id="floatingSelect"> |
|||
<option selected>Vyberte...</option> |
|||
<option value="1">Option 1</option> |
|||
<option value="2">Option 2</option> |
|||
</select> |
|||
<label for="floatingSelect">Výběr</label> |
|||
</div> |
|||
|
|||
<div class="form-floating mb-3"> |
|||
<textarea class="form-control" placeholder="Zpráva" id="floatingTextarea" style="height: 100px"></textarea> |
|||
<label for="floatingTextarea">Zpráva</label> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- PROJEKT PRO STUDENTY --> |
|||
<div class="demo-section bg-warning bg-opacity-10" id="projekt"> |
|||
<h2 class="demo-title text-danger">🎯 PROJEKT PRO VÁS: Kontaktní formulář</h2> |
|||
<div class="alert alert-danger"> |
|||
<h4>📝 Zadání:</h4> |
|||
<p>Vytvořte vlastní kontaktní formulář s těmito požadavky:</p> |
|||
<ol> |
|||
<li><strong>Pole:</strong> Jméno, Email, Telefon, Předmět, Zpráva</li> |
|||
<li><strong>Validace:</strong> Všechna pole povinná (kromě Telefon)</li> |
|||
<li><strong>Telefon:</strong> Pattern pro české číslo (9 číslic)</li> |
|||
<li><strong>Email:</strong> Správný email formát</li> |
|||
<li><strong>Zpráva:</strong> Minimálně 10 znaků</li> |
|||
<li><strong>Vzhled:</strong> Použijte Floating labels</li> |
|||
<li><strong>Bonus:</strong> Přidejte Input group k telefonu (+420)</li> |
|||
<li><strong>Submit:</strong> Při úspěšném odeslání zobrazte Alert</li> |
|||
</ol> |
|||
<p class="mb-0"><strong>Vytvořte nový soubor:</strong> <code>muj_formular.html</code></p> |
|||
</div> |
|||
</div> |
|||
|
|||
</main> |
|||
|
|||
<!-- Footer --> |
|||
<footer class="footer mt-auto py-3 bg-light"> |
|||
<div class="container text-center"> |
|||
<span class="text-muted">Bootstrap Forms & Validace | WTL 2025</span> |
|||
</div> |
|||
</footer> |
|||
|
|||
<!-- JAVASCRIPT pro validaci --> |
|||
<script src="js/bootstrap.bundle.js"></script> |
|||
<script> |
|||
// ===== VALIDACE REGISTRAČNÍHO FORMULÁŘE ===== |
|||
|
|||
// Najdeme formulář |
|||
const form = document.getElementById('registrationForm'); |
|||
const successMessage = document.getElementById('successMessage'); |
|||
|
|||
// Přidáme event listener na submit |
|||
form.addEventListener('submit', function(event) { |
|||
// Zastavíme defaultní odeslání formuláře |
|||
event.preventDefault(); |
|||
event.stopPropagation(); |
|||
|
|||
// Speciální validace: hesla se musí shodovat |
|||
const heslo = document.getElementById('regHeslo'); |
|||
const heslo2 = document.getElementById('regHeslo2'); |
|||
|
|||
if (heslo.value !== heslo2.value) { |
|||
heslo2.setCustomValidity('Hesla se neshodují'); |
|||
} else { |
|||
heslo2.setCustomValidity(''); |
|||
} |
|||
|
|||
// Zkontrolujeme validitu formuláře |
|||
if (form.checkValidity()) { |
|||
// Formulář je validní - zobrazíme success zprávu |
|||
form.classList.add('was-validated'); |
|||
successMessage.style.display = 'block'; |
|||
|
|||
// Scrollujeme ke zprávě |
|||
successMessage.scrollIntoView({ behavior: 'smooth' }); |
|||
|
|||
// Resetujeme formulář po 3 sekundách |
|||
setTimeout(function() { |
|||
form.reset(); |
|||
form.classList.remove('was-validated'); |
|||
successMessage.style.display = 'none'; |
|||
}, 3000); |
|||
} else { |
|||
// Formulář není validní - zobrazíme chyby |
|||
form.classList.add('was-validated'); |
|||
successMessage.style.display = 'none'; |
|||
} |
|||
}); |
|||
|
|||
// Real-time validace hesel |
|||
document.getElementById('regHeslo2').addEventListener('input', function() { |
|||
const heslo = document.getElementById('regHeslo'); |
|||
const heslo2 = this; |
|||
|
|||
if (heslo.value !== heslo2.value) { |
|||
heslo2.setCustomValidity('Hesla se neshodují'); |
|||
} else { |
|||
heslo2.setCustomValidity(''); |
|||
} |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -0,0 +1,280 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Kontaktní Formulář - Řešení</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
</head> |
|||
<body class="d-flex flex-column min-vh-100"> |
|||
<!-- Header --> |
|||
<div class="container"> |
|||
<header class="d-flex flex-wrap justify-content-center py-3 mb-3 border-bottom"> |
|||
<a href="#" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none fs-4"> |
|||
Kontaktní Formulář |
|||
</a> |
|||
<ul class="nav nav-pills"> |
|||
<li class="nav-item"><a href="index.html" class="nav-link">Zpět na příklady</a></li> |
|||
<li class="nav-item"><a href="template.html" class="nav-link">Šablona</a></li> |
|||
</ul> |
|||
</header> |
|||
</div> |
|||
|
|||
<!-- MAIN --> |
|||
<main class="container"> |
|||
<div class="row justify-content-center"> |
|||
<div class="col-lg-8"> |
|||
<h1 class="display-5 mb-2">📧 Kontaktujte nás</h1> |
|||
<p class="text-muted mb-4">Vyplňte formulář níže a ozveme se vám co nejdříve.</p> |
|||
|
|||
<!-- Kontaktní formulář --> |
|||
<form id="contactForm" class="needs-validation" novalidate> |
|||
|
|||
<!-- Jméno - Floating label --> |
|||
<div class="form-floating mb-3"> |
|||
<input type="text" |
|||
class="form-control" |
|||
id="jmeno" |
|||
placeholder="Jméno" |
|||
required> |
|||
<label for="jmeno">Jméno *</label> |
|||
<div class="invalid-feedback"> |
|||
Prosím vyplňte vaše jméno. |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Email - Floating label --> |
|||
<div class="form-floating mb-3"> |
|||
<input type="email" |
|||
class="form-control" |
|||
id="email" |
|||
placeholder="Email" |
|||
required> |
|||
<label for="email">Email *</label> |
|||
<div class="invalid-feedback"> |
|||
Prosím zadejte platnou emailovou adresu. |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Telefon - Input group s +420 a pattern pro 9 číslic --> |
|||
<div class="mb-3"> |
|||
<label for="telefon" class="form-label">Telefon (nepovinné)</label> |
|||
<div class="input-group"> |
|||
<span class="input-group-text">+420</span> |
|||
<input type="tel" |
|||
class="form-control" |
|||
id="telefon" |
|||
placeholder="123456789" |
|||
pattern="[0-9]{9}"> |
|||
<div class="invalid-feedback"> |
|||
Zadejte telefonní číslo ve formátu 123456789 (9 číslic). |
|||
</div> |
|||
</div> |
|||
<div class="form-text">Formát: 9 číslic bez mezer (např. 777123456)</div> |
|||
</div> |
|||
|
|||
<!-- Předmět - Floating select --> |
|||
<div class="form-floating mb-3"> |
|||
<select class="form-select" id="predmet" required> |
|||
<option value="">Vyberte předmět...</option> |
|||
<option value="dotaz">Obecný dotaz</option> |
|||
<option value="podpora">Technická podpora</option> |
|||
<option value="objednavka">Objednávka</option> |
|||
<option value="reklamace">Reklamace</option> |
|||
<option value="jine">Jiné</option> |
|||
</select> |
|||
<label for="predmet">Předmět *</label> |
|||
<div class="invalid-feedback"> |
|||
Vyberte prosím předmět zprávy. |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Zpráva - Floating textarea s minlength 10 --> |
|||
<div class="form-floating mb-3"> |
|||
<textarea class="form-control" |
|||
id="zprava" |
|||
placeholder="Zpráva" |
|||
style="height: 150px" |
|||
minlength="10" |
|||
required></textarea> |
|||
<label for="zprava">Zpráva * (min. 10 znaků)</label> |
|||
<div class="invalid-feedback"> |
|||
Zpráva musí obsahovat alespoň 10 znaků. |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- GDPR souhlas --> |
|||
<div class="mb-4 form-check"> |
|||
<input type="checkbox" |
|||
class="form-check-input" |
|||
id="souhlas" |
|||
required> |
|||
<label class="form-check-label" for="souhlas"> |
|||
Souhlasím se zpracováním osobních údajů * |
|||
</label> |
|||
<div class="invalid-feedback"> |
|||
Musíte souhlasit se zpracováním osobních údajů. |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Submit button --> |
|||
<div class="d-grid gap-2"> |
|||
<button type="submit" class="btn btn-primary btn-lg"> |
|||
📨 Odeslat zprávu |
|||
</button> |
|||
</div> |
|||
|
|||
<p class="text-muted mt-3 small">* = povinné pole</p> |
|||
</form> |
|||
|
|||
<!-- Success Alert (skrytý, zobrazí se po úspěšném odeslání) --> |
|||
<div id="successAlert" class="alert alert-success alert-dismissible fade show mt-4" style="display: none;"> |
|||
<h4 class="alert-heading">✅ Zpráva byla odeslána!</h4> |
|||
<p>Děkujeme za váš kontakt. Ozveme se vám co nejdříve.</p> |
|||
<hr> |
|||
<p class="mb-0">Obvykle odpovídáme do 24 hodin.</p> |
|||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button> |
|||
</div> |
|||
|
|||
<!-- Info sekce --> |
|||
<div class="card mt-5 bg-light"> |
|||
<div class="card-body"> |
|||
<h5 class="card-title">📞 Další kontaktní možnosti</h5> |
|||
<ul class="list-unstyled mb-0"> |
|||
<li>📧 Email: info@example.cz</li> |
|||
<li>☎️ Telefon: +420 123 456 789</li> |
|||
<li>🏢 Adresa: Praha 1, Václavské náměstí 1</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</main> |
|||
|
|||
<!-- Footer --> |
|||
<footer class="footer mt-auto py-3 bg-light"> |
|||
<div class="container text-center"> |
|||
<span class="text-muted">Kontaktní Formulář - Řešení | WTL 2025</span> |
|||
</div> |
|||
</footer> |
|||
|
|||
<script src="js/bootstrap.bundle.js"></script> |
|||
<script> |
|||
// ===== JAVASCRIPT VALIDACE ===== |
|||
|
|||
// 1. Najdeme formulář a success alert |
|||
const contactForm = document.getElementById('contactForm'); |
|||
const successAlert = document.getElementById('successAlert'); |
|||
|
|||
// 2. Přidáme event listener na odeslání formuláře |
|||
contactForm.addEventListener('submit', function(event) { |
|||
// Zastavíme defaultní odeslání formuláře |
|||
event.preventDefault(); |
|||
event.stopPropagation(); |
|||
|
|||
// 3. Zkontrolujeme validitu formuláře |
|||
if (contactForm.checkValidity()) { |
|||
// ✅ Formulář je validní |
|||
|
|||
// Přidáme třídu pro zobrazení validních polí |
|||
contactForm.classList.add('was-validated'); |
|||
|
|||
// Zobrazíme success zprávu |
|||
successAlert.style.display = 'block'; |
|||
|
|||
// Scrollujeme k success zprávě |
|||
successAlert.scrollIntoView({ behavior: 'smooth', block: 'center' }); |
|||
|
|||
// BONUS: Vypíšeme data z formuláře do console |
|||
console.log('=== DATA Z FORMULÁŘE ==='); |
|||
console.log('Jméno:', document.getElementById('jmeno').value); |
|||
console.log('Email:', document.getElementById('email').value); |
|||
console.log('Telefon:', document.getElementById('telefon').value || 'nevyplněno'); |
|||
console.log('Předmět:', document.getElementById('predmet').value); |
|||
console.log('Zpráva:', document.getElementById('zprava').value); |
|||
console.log('Souhlas GDPR:', document.getElementById('souhlas').checked); |
|||
|
|||
// Resetujeme formulář po 4 sekundách |
|||
setTimeout(function() { |
|||
contactForm.reset(); |
|||
contactForm.classList.remove('was-validated'); |
|||
successAlert.style.display = 'none'; |
|||
}, 4000); |
|||
|
|||
} else { |
|||
// ❌ Formulář není validní |
|||
|
|||
// Přidáme třídu pro zobrazení chyb |
|||
contactForm.classList.add('was-validated'); |
|||
|
|||
// Skryjeme success zprávu (kdyby byla zobrazená) |
|||
successAlert.style.display = 'none'; |
|||
|
|||
// Najdeme první invalidní pole a scrollujeme k němu |
|||
const firstInvalid = contactForm.querySelector(':invalid'); |
|||
if (firstInvalid) { |
|||
firstInvalid.focus(); |
|||
firstInvalid.scrollIntoView({ behavior: 'smooth', block: 'center' }); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// ===== BONUS: Real-time validace pro telefon ===== |
|||
// Zobrazíme feedback už při psaní (ne až po submitu) |
|||
const telefonInput = document.getElementById('telefon'); |
|||
|
|||
telefonInput.addEventListener('input', function() { |
|||
// Pokud je pole prázdné, je to OK (není required) |
|||
if (this.value === '') { |
|||
this.classList.remove('is-invalid'); |
|||
this.classList.remove('is-valid'); |
|||
return; |
|||
} |
|||
|
|||
// Zkontrolujeme pattern (9 číslic) |
|||
const pattern = /^[0-9]{9}$/; |
|||
|
|||
if (pattern.test(this.value)) { |
|||
this.classList.remove('is-invalid'); |
|||
this.classList.add('is-valid'); |
|||
} else { |
|||
this.classList.remove('is-valid'); |
|||
this.classList.add('is-invalid'); |
|||
} |
|||
}); |
|||
|
|||
// ===== BONUS: Počítadlo znaků u zprávy ===== |
|||
const zpravaInput = document.getElementById('zprava'); |
|||
|
|||
// Vytvoříme element pro zobrazení počtu znaků |
|||
const counterDiv = document.createElement('div'); |
|||
counterDiv.className = 'form-text'; |
|||
counterDiv.id = 'zpravaCounter'; |
|||
zpravaInput.parentElement.appendChild(counterDiv); |
|||
|
|||
// Funkce pro update počítadla |
|||
function updateCounter() { |
|||
const length = zpravaInput.value.length; |
|||
const min = 10; |
|||
|
|||
if (length === 0) { |
|||
counterDiv.textContent = `Napište zprávu (min. ${min} znaků)`; |
|||
counterDiv.className = 'form-text'; |
|||
} else if (length < min) { |
|||
counterDiv.textContent = `${length}/${min} znaků - ještě ${min - length} znaků`; |
|||
counterDiv.className = 'form-text text-danger'; |
|||
} else { |
|||
counterDiv.textContent = `${length} znaků ✓`; |
|||
counterDiv.className = 'form-text text-success'; |
|||
} |
|||
} |
|||
|
|||
// Zavoláme hned na začátku |
|||
updateCounter(); |
|||
|
|||
// A při každé změně |
|||
zpravaInput.addEventListener('input', updateCounter); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,128 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Bootstrap Formulář - Šablona</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
</head> |
|||
<body class="d-flex flex-column min-vh-100"> |
|||
<!-- Header --> |
|||
<div class="container"> |
|||
<header class="d-flex flex-wrap justify-content-center py-3 mb-3 border-bottom"> |
|||
<a href="#" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none fs-4"> |
|||
Můj Formulář |
|||
</a> |
|||
<ul class="nav nav-pills"> |
|||
<li class="nav-item"><a href="index.html" class="nav-link">Zpět na příklady</a></li> |
|||
</ul> |
|||
</header> |
|||
</div> |
|||
|
|||
<!-- MAIN --> |
|||
<main class="container"> |
|||
<h1 class="display-4 mb-4">🚀 Startovací šablona pro váš projekt</h1> |
|||
|
|||
<div class="row"> |
|||
<div class="col-md-8"> |
|||
<!-- TODO: Zde vytvořte svůj formulář --> |
|||
<form id="myForm" class="needs-validation" novalidate> |
|||
|
|||
<!-- Příklad jednoho pole - můžete použít jako vzor --> |
|||
<div class="mb-3"> |
|||
<label for="exampleInput" class="form-label">Ukázkové pole:</label> |
|||
<input type="text" class="form-control" id="exampleInput" required> |
|||
<div class="invalid-feedback"> |
|||
Toto pole je povinné. |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- TODO: Přidejte další pole podle zadání --> |
|||
|
|||
|
|||
<button type="submit" class="btn btn-primary">Odeslat</button> |
|||
</form> |
|||
|
|||
<!-- Success zpráva --> |
|||
<div id="successAlert" class="alert alert-success mt-4" style="display: none;"> |
|||
<h4>✅ Formulář odeslán!</h4> |
|||
<p>Všechna pole byla vyplněna správně.</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-md-4"> |
|||
<!-- Nápověda --> |
|||
<div class="card bg-light"> |
|||
<div class="card-body"> |
|||
<h5 class="card-title">💡 Nápověda</h5> |
|||
<h6>Bootstrap třídy:</h6> |
|||
<ul class="small"> |
|||
<li><code>form-control</code> - pro input, textarea</li> |
|||
<li><code>form-select</code> - pro select</li> |
|||
<li><code>form-label</code> - pro label</li> |
|||
<li><code>form-check-input</code> - pro checkbox/radio</li> |
|||
<li><code>invalid-feedback</code> - chybová zpráva</li> |
|||
<li><code>valid-feedback</code> - úspěšná zpráva</li> |
|||
</ul> |
|||
|
|||
<h6 class="mt-3">HTML atributy:</h6> |
|||
<ul class="small"> |
|||
<li><code>required</code> - povinné pole</li> |
|||
<li><code>minlength="X"</code> - min počet znaků</li> |
|||
<li><code>maxlength="X"</code> - max počet znaků</li> |
|||
<li><code>pattern="..."</code> - regex vzor</li> |
|||
<li><code>min="X"</code> - minimální hodnota</li> |
|||
<li><code>max="X"</code> - maximální hodnota</li> |
|||
</ul> |
|||
|
|||
<h6 class="mt-3">Užitečné vzory (pattern):</h6> |
|||
<ul class="small"> |
|||
<li>Tel.: <code>[0-9]{9}</code></li> |
|||
<li>PSČ: <code>[0-9]{5}</code></li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</main> |
|||
|
|||
<!-- Footer --> |
|||
<footer class="footer mt-auto py-3 bg-light"> |
|||
<div class="container text-center"> |
|||
<span class="text-muted">Vytvořil/a: [VAŠE JMÉNO] | WTL 2025</span> |
|||
</div> |
|||
</footer> |
|||
|
|||
<script src="js/bootstrap.bundle.js"></script> |
|||
<script> |
|||
// TODO: Zde přidejte JavaScript pro validaci |
|||
|
|||
const form = document.getElementById('myForm'); |
|||
const successAlert = document.getElementById('successAlert'); |
|||
|
|||
form.addEventListener('submit', function(event) { |
|||
event.preventDefault(); |
|||
event.stopPropagation(); |
|||
|
|||
// TODO: Přidejte vlastní validaci (např. porovnání hesel) |
|||
|
|||
if (form.checkValidity()) { |
|||
// Formulář je validní |
|||
form.classList.add('was-validated'); |
|||
successAlert.style.display = 'block'; |
|||
|
|||
// Resetovat formulář po 3 sekundách |
|||
setTimeout(function() { |
|||
form.reset(); |
|||
form.classList.remove('was-validated'); |
|||
successAlert.style.display = 'none'; |
|||
}, 3000); |
|||
} else { |
|||
// Formulář není validní |
|||
form.classList.add('was-validated'); |
|||
successAlert.style.display = 'none'; |
|||
} |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,208 @@ |
|||
# Rychlý návod - XSS Demo (Zjednodušená verze) |
|||
|
|||
## 📁 Jednoduché soubory pro rychlou demonstraci: |
|||
|
|||
### ⚠️ `zranitelna_jednoducha.html` - NEBEZPEČNÁ |
|||
- Minimální kód |
|||
- Používá `innerHTML` - lze hacknout! |
|||
- Útoky připravené v pravém sloupci |
|||
|
|||
### ✅ `bezpecna_jednoducha.html` - BEZPEČNÁ |
|||
- Minimální kód |
|||
- Používá `textContent` - nelze hacknout! |
|||
- Zobrazí XSS útoky jako text |
|||
|
|||
--- |
|||
|
|||
## 🎯 Jak demonstrovat (5 minut): |
|||
|
|||
### 1. Otevřete `zranitelna_jednoducha.html` |
|||
|
|||
### 2. Zkopírujte tento útok do pole "Zpráva": |
|||
```html |
|||
<img src=x onerror="alert('HACKNUTÝ!')"> |
|||
``` |
|||
**POZOR:** Nepoužívejte `<script>` - prohlížeč ho zablokuje! Používejte event handlery! |
|||
|
|||
### 3. Klikněte "Přidat záznam" |
|||
- **💥 Alert se zobrazí! = ÚTOK USPĚL!** |
|||
|
|||
### 4. Otevřete `bezpecna_jednoducha.html` |
|||
|
|||
### 5. Zkuste stejný útok |
|||
- ✅ **Zobrazí se jako text, nespustí se!** |
|||
|
|||
--- |
|||
|
|||
## 💡 Další fungující útoky k vyzkoušení: |
|||
|
|||
```html |
|||
<!-- Změna pozadí na červenou --> |
|||
<img src=x onerror="document.body.style.background='red'"> |
|||
|
|||
<!-- Velký červený nápis --> |
|||
<h1 style="color:red; font-size:50px">HACKED!</h1> |
|||
|
|||
<!-- SVG útok --> |
|||
<svg onload="alert('XSS')"> |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 💡 Co dělá `e.preventDefault()`? |
|||
|
|||
```javascript |
|||
form.addEventListener('submit', function(e) { |
|||
e.preventDefault(); // ← CO TO DĚLÁ? |
|||
|
|||
// ... zbytek kódu |
|||
}); |
|||
``` |
|||
|
|||
### Bez `e.preventDefault()`: |
|||
1. Kliknete "Odeslat" |
|||
2. Formulář se odešle na server |
|||
3. Stránka se **OBNOVÍ** (reload) |
|||
4. Ztratíte všechna data! |
|||
|
|||
### S `e.preventDefault()`: |
|||
1. Kliknete "Odeslat" |
|||
2. **ZASTAVÍ** normální odeslání |
|||
3. Stránka se **NEOBNOVÍ** |
|||
4. Můžete zpracovat data v JavaScriptu! |
|||
|
|||
### Příklad: |
|||
```javascript |
|||
// ❌ BEZ preventDefault - stránka se obnoví |
|||
form.addEventListener('submit', function(e) { |
|||
console.log('Odesláno!'); |
|||
// → Stránka se obnoví a nic neuvidíte! |
|||
}); |
|||
|
|||
// ✅ S preventDefault - stránka zůstane |
|||
form.addEventListener('submit', function(e) { |
|||
e.preventDefault(); // Zastaví refresh! |
|||
console.log('Odesláno!'); |
|||
// → Zpráva se zobrazí v konzoli! |
|||
}); |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 🔍 Porovnání kódu: |
|||
|
|||
### ❌ NEBEZPEČNÉ (innerHTML): |
|||
```javascript |
|||
const html = `<p><strong>${name}</strong>: ${message}</p>`; |
|||
entriesDiv.innerHTML += html; // SPUSTÍ JavaScript! |
|||
``` |
|||
|
|||
### ✅ BEZPEČNÉ (textContent): |
|||
```javascript |
|||
const div = document.createElement('div'); |
|||
const strong = document.createElement('strong'); |
|||
strong.textContent = name; // JEN TEXT, ne kód! |
|||
|
|||
const text = document.createElement('span'); |
|||
text.textContent = ': ' + message; // JEN TEXT! |
|||
|
|||
div.appendChild(strong); |
|||
div.appendChild(text); |
|||
entriesDiv.appendChild(div); |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 🎓 Pro studenty: |
|||
|
|||
### Zapamatujte si: |
|||
|
|||
1. **innerHTML = NEBEZPEČNÉ** ❌ |
|||
- Spustí HTML a JavaScript |
|||
|
|||
2. **textContent = BEZPEČNÉ** ✅ |
|||
- Zobrazí jen čistý text |
|||
|
|||
3. **createElement() = BEZPEČNÉ** ✅ |
|||
- Vytvoří čisté DOM elementy |
|||
|
|||
4. **Zlaté pravidlo:** |
|||
``` |
|||
🚨 DON'T TRUST THE INPUT! 🚨 |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 🚀 XSS útoky k vyzkoušení: |
|||
|
|||
### ✅ FUNGUJÍCÍ útoky (použijte tyto!): |
|||
|
|||
```html |
|||
<!-- 1. IMG útok - FUNGUJE! --> |
|||
<img src=x onerror="alert('HACKNUTÝ!')"> |
|||
|
|||
<!-- 2. Změna pozadí - FUNGUJE! --> |
|||
<img src=x onerror="document.body.style.background='red'"> |
|||
|
|||
<!-- 3. SVG útok - FUNGUJE! --> |
|||
<svg onload="alert('XSS')"> |
|||
|
|||
<!-- 4. Input útok - FUNGUJE! --> |
|||
<input onfocus="alert('XSS')" autofocus> |
|||
|
|||
<!-- 5. Změna HTML (bez JS) - FUNGUJE! --> |
|||
<h1 style="color:red; font-size:50px">HACKED!</h1> |
|||
``` |
|||
|
|||
### ❌ NEFUNGUJÍCÍ útoky (prohlížeč blokuje): |
|||
|
|||
```html |
|||
<!-- Script tag v innerHTML - NEFUNGUJE! --> |
|||
<script>alert('XSS')</script> |
|||
<!-- Prohlížeč tohle automaticky zablokuje --> |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 🔍 DŮLEŽITÉ: Proč `<script>` nefunguje? |
|||
|
|||
### Bezpečnostní opatření prohlížečů: |
|||
|
|||
**`<script>` tagy přidané přes `innerHTML` se NESPUSTÍ!** |
|||
|
|||
```javascript |
|||
// ❌ Toto NESPUSTÍ JavaScript: |
|||
element.innerHTML = '<script>alert(1)</script>'; |
|||
``` |
|||
|
|||
**Proč?** Moderní prohlížeče (Chrome, Firefox, Edge) mají bezpečnostní ochranu. |
|||
|
|||
### ALE! Event handlery FUNGUJÍ: |
|||
|
|||
```javascript |
|||
// ✅ Toto SPUSTÍ JavaScript: |
|||
element.innerHTML = '<img src=x onerror="alert(1)">'; |
|||
``` |
|||
|
|||
**Proto je innerHTML STÁLE nebezpečné!** |
|||
|
|||
Útočníci nepoužívají `<script>`, ale: |
|||
- `onerror` (img, video, audio) |
|||
- `onload` (svg, iframe, body) |
|||
- `onfocus` (input, textarea) |
|||
- `onmouseover` (div, span, a) |
|||
- atd. |
|||
|
|||
--- |
|||
|
|||
--- |
|||
|
|||
## ⚠️ DŮLEŽITÉ! |
|||
|
|||
- Toto je **jen pro vzdělávání** |
|||
- **NIKDY** nepoužívejte zranitelný kód v produkci |
|||
- Hacking bez povolení = **TRESTNÝ ČIN** |
|||
|
|||
--- |
|||
|
|||
**Hotovo! Teď máte jednoduchou demonstraci XSS útoku.** 🎯 |
|||
@ -0,0 +1,377 @@ |
|||
# Lekce 18a: XSS Demo - "Don't Trust The Input" |
|||
|
|||
## 🎯 Cíl lekce |
|||
|
|||
**Naučit studenty základy bezpečnosti webových aplikací** prostřednictvím praktické demonstrace XSS (Cross-Site Scripting) útoku. Studenti pochopí: |
|||
- Proč je důležité ošetřovat vstup od uživatelů |
|||
- Rozdíl mezi `innerHTML` (nebezpečné) a `textContent` (bezpečné) |
|||
- Pravidlo **"DON'T TRUST THE INPUT"** |
|||
|
|||
## ⚠️ DŮLEŽITÉ UPOZORNĚNÍ |
|||
|
|||
Tato lekce obsahuje **ZÁMĚRNĚ ZRANITELNÝ KÓD** pro vzdělávací účely! |
|||
- ❌ **NIKDY** nepoužívejte zranitelnou verzi v produkčním prostředí |
|||
- ✅ Vysvětlete studentům, že jde o **demonstraci bezpečnostní chyby** |
|||
- ✅ Zdůrazněte, že **hacking bez povolení je TRESTNÝ ČIN** |
|||
|
|||
## 📁 Soubory v této lekci |
|||
|
|||
### 1. `index.html` - Úvodní stránka |
|||
- Přehled lekce |
|||
- Vysvětlení XSS |
|||
- Porovnání nebezpečného vs. bezpečného kódu |
|||
- Doporučený postup lekce |
|||
|
|||
### 2. `zranitelna_verze.html` - NEBEZPEČNÁ verze |
|||
- Návštěvní kniha s formulářem |
|||
- **Používá `innerHTML`** - umožňuje XSS útoky! |
|||
- V pravém sloupci jsou připravené XSS útoky ke zkopírování |
|||
- Červené varování nahoře |
|||
|
|||
### 3. `bezpecna_verze.html` - BEZPEČNÁ verze |
|||
- Stejná návštěvní kniha |
|||
- **Používá `textContent` a `createElement()`** |
|||
- XSS útoky zde nefungují |
|||
- Zelené potvrzení bezpečnosti |
|||
- Detailní vysvětlení bezpečného kódu |
|||
|
|||
## 🎓 Postup výuky (60 minut) |
|||
|
|||
### Fáze 1: Úvod (10 min) |
|||
|
|||
1. **Otevřete `index.html`** na projektoru |
|||
2. **Zeptejte se studentů:** |
|||
- "Myslíte si, že formuláře na webu jsou bezpečné?" |
|||
- "Co když útočník zadá do formuláře škodlivý kód?" |
|||
- "Slyšeli jste o XSS útoku?" |
|||
|
|||
3. **Vysvětlete XSS:** |
|||
- Cross-Site Scripting |
|||
- Útočník vkládá škodlivý kód do webové stránky |
|||
- Kód se spustí v prohlížeči jiného uživatele |
|||
- Může ukrást hesla, cookies, osobní data |
|||
|
|||
4. **Ukažte zlaté pravidlo:** |
|||
``` |
|||
🚨 "DON'T TRUST THE INPUT" 🚨 |
|||
Nikdy nedůvěřujte tomu, co uživatel zadá! |
|||
``` |
|||
|
|||
### Fáze 2: Demonstrace útoku (20 min) |
|||
|
|||
1. **Otevřete `zranitelna_verze.html`** |
|||
|
|||
2. **Základní funkce (2 min):** |
|||
- Ukažte normální použití formuláře |
|||
- Zadejte běžné jméno a zprávu |
|||
- Uveďte: "Takto to vypadá normálně" |
|||
|
|||
3. **ÚTOK #1 - Alert (3 min):** |
|||
```html |
|||
<script>alert('Byl jsi hacknutý!')</script> |
|||
``` |
|||
- Zkopírujte do pole "Zpráva" |
|||
- Odešlete formulář |
|||
- **BOOM! Alert se zobrazí!** 💥 |
|||
- Vysvětlete: "To je XSS útok! JavaScript se spustil!" |
|||
|
|||
4. **ÚTOK #2 - Změna stránky (3 min):** |
|||
```html |
|||
<h1 style="color:red; font-size:60px;">HACKED!</h1> |
|||
``` |
|||
- Vložte do formuláře |
|||
- Odešlete |
|||
- Stránka se vizuálně změní |
|||
- Vysvětlete: "Útočník změnil HTML strukturu!" |
|||
|
|||
5. **ÚTOK #3 - Krádež cookies (5 min):** |
|||
```html |
|||
<script>alert('Tvoje cookies: ' + document.cookie)</script> |
|||
``` |
|||
- Vložte do formuláře |
|||
- Alert zobrazí cookies |
|||
- **KRITICKY DŮLEŽITÉ:** Vysvětlete, že v cookies mohou být: |
|||
- Session ID (přihlášení) |
|||
- Tokeny |
|||
- Osobní data |
|||
- Útočník může cookies odeslat na svůj server! |
|||
|
|||
6. **ÚTOK #4 - Obrázek s onerror (3 min):** |
|||
```html |
|||
<img src=x onerror="alert('XSS útok přes obrázek!')"> |
|||
``` |
|||
- Tento útok funguje i když admin zakáže `<script>` |
|||
- Ukažte, že útočníci jsou kreativní |
|||
|
|||
7. **Diskuze (4 min):** |
|||
- "Co si myslíte, co by se stalo na skutečném webu?" |
|||
- "Co by mohl útočník udělat s vašimi přihlašovacími údaji?" |
|||
- "Je to nebezpečné?" |
|||
|
|||
### Fáze 3: Bezpečné řešení (15 min) |
|||
|
|||
1. **Otevřete `bezpecna_verze.html`** |
|||
|
|||
2. **Zkuste stejné útoky (5 min):** |
|||
- Vložte `<script>alert('XSS')</script>` |
|||
- Nefunguje! Zobrazí se jako text! ✅ |
|||
- Zkuste další útoky - žádný nefunguje |
|||
|
|||
3. **Vysvětlete rozdíl (5 min):** |
|||
- Scrollujte dolů k sekci "Jak to funguje?" |
|||
- Ukažte rozdíl v kódu: |
|||
|
|||
**NEBEZPEČNÉ:** |
|||
```javascript |
|||
element.innerHTML = `<p>${message}</p>`; |
|||
// innerHTML SPUSTÍ JavaScript! |
|||
``` |
|||
|
|||
**BEZPEČNÉ:** |
|||
```javascript |
|||
const p = document.createElement('p'); |
|||
p.textContent = message; |
|||
element.appendChild(p); |
|||
// textContent NESPUSTÍ JavaScript! |
|||
``` |
|||
|
|||
4. **Projděte bezpečný kód (5 min):** |
|||
- Ukažte použití `createElement()` |
|||
- Ukažte použití `textContent` |
|||
- Vysvětlete: "HTML se zobrazí jako TEXT, ne jako KÓD" |
|||
|
|||
### Fáze 4: Praktické cvičení (10 min) |
|||
|
|||
**Zadání pro studenty:** |
|||
1. Otevřete oba soubory vedle sebe |
|||
2. Porovnejte JavaScript kód |
|||
3. Najděte všechny rozdíly |
|||
4. Napište do poznámek: |
|||
- Co je nebezpečné? |
|||
- Co je bezpečné? |
|||
- Proč? |
|||
|
|||
### Fáze 5: Shrnutí a test (5 min) |
|||
|
|||
**Otázky pro studenty:** |
|||
1. ❓ "Co znamená XSS?" |
|||
- ✅ Cross-Site Scripting |
|||
|
|||
2. ❓ "Proč je `innerHTML` nebezpečné?" |
|||
- ✅ Spouští HTML a JavaScript kód |
|||
|
|||
3. ❓ "Co je bezpečnější: `innerHTML` nebo `textContent`?" |
|||
- ✅ `textContent` |
|||
|
|||
4. ❓ "Jaké je zlaté pravidlo bezpečnosti?" |
|||
- ✅ "DON'T TRUST THE INPUT" |
|||
|
|||
5. ❓ "Můžu důvěřovat tomu, co uživatel zadá do formuláře?" |
|||
- ✅ NE! NIKDY! |
|||
|
|||
## 🎯 XSS útoky k vyzkoušení |
|||
|
|||
### Základní útoky (pro všechny studenty): |
|||
|
|||
```html |
|||
<!-- 1. Jednoduchý alert --> |
|||
<script>alert('XSS útok!')</script> |
|||
|
|||
<!-- 2. Změna textu --> |
|||
<h1 style="color:red;">HACKED!</h1> |
|||
|
|||
<!-- 3. Změna pozadí --> |
|||
<script>document.body.style.background = 'red'</script> |
|||
|
|||
<!-- 4. Obrázek s chybou --> |
|||
<img src=x onerror="alert('XSS')"> |
|||
|
|||
<!-- 5. Zobrazení cookies --> |
|||
<script>alert(document.cookie)</script> |
|||
``` |
|||
|
|||
### Pokročilé útoky (pro šikovnější studenty): |
|||
|
|||
```html |
|||
<!-- 6. Přesměrování --> |
|||
<script>window.location = 'https://google.com'</script> |
|||
|
|||
<!-- 7. Změna HTML --> |
|||
<script>document.body.innerHTML = '<h1>Byl jsi hacknutý!</h1>'</script> |
|||
|
|||
<!-- 8. Infinite loop (pozor, může zhavarovat!) --> |
|||
<script>while(true){alert('SPAM')}</script> |
|||
|
|||
<!-- 9. Console log spam --> |
|||
<script>setInterval(()=>console.log('HACKED'), 100)</script> |
|||
|
|||
<!-- 10. Krádež formulářových dat --> |
|||
<script> |
|||
const data = document.getElementById('name').value; |
|||
alert('Ukradl jsem: ' + data); |
|||
</script> |
|||
``` |
|||
|
|||
### Kreativní útoky (bonus): |
|||
|
|||
```html |
|||
<!-- 11. Falešný login formulář --> |
|||
<div style="position:fixed; top:0; left:0; width:100%; height:100%; background:white; z-index:9999;"> |
|||
<h1>Přihlášení vypršelo</h1> |
|||
<input type="text" placeholder="Uživatel"> |
|||
<input type="password" placeholder="Heslo"> |
|||
<button>Přihlásit</button> |
|||
</div> |
|||
|
|||
<!-- 12. Vibrace (na mobilu) --> |
|||
<script>navigator.vibrate([200, 100, 200])</script> |
|||
|
|||
<!-- 13. Text-to-speech (pokud podporováno) --> |
|||
<script> |
|||
const utterance = new SpeechSynthesisUtterance('Byl jsi hacknutý!'); |
|||
speechSynthesis.speak(utterance); |
|||
</script> |
|||
``` |
|||
|
|||
## 📊 Hodnocení (doporučené) |
|||
|
|||
Pokud chcete lekci ohodnotit, můžete použít tento systém: |
|||
|
|||
### Praktický test (10 bodů): |
|||
|
|||
1. **Identifikace problému (3b)** |
|||
- Student najde `innerHTML` v nebezpečném kódu |
|||
- Vysvětlí proč je to problém |
|||
|
|||
2. **Provedení útoku (2b)** |
|||
- Student úspěšně provede XSS útok na zranitelné verzi |
|||
|
|||
3. **Obrana (3b)** |
|||
- Student vysvětlí jak se bránit |
|||
- Zmíní `textContent` nebo `createElement()` |
|||
|
|||
4. **Pravidlo (2b)** |
|||
- Student zná a umí vysvětlit "Don't Trust The Input" |
|||
|
|||
## 💡 Tipy pro učitele |
|||
|
|||
### Při výuce: |
|||
|
|||
1. **Dramatizujte:** |
|||
- Když se spustí XSS útok, reagujte: "Oh ne! Stránka je kompromitovaná!" |
|||
- Studenti si to lépe zapamatují |
|||
|
|||
2. **Real-world příklady:** |
|||
- Facebook měl XSS zranitelnost v 2011 |
|||
- Twitter XSS worm v 2010 |
|||
- eBay XSS v 2014 |
|||
|
|||
3. **Etika:** |
|||
- **DŮLEŽITÉ:** Zdůrazněte, že hacking bez povolení je TRESTNÝ ČIN |
|||
- Vysvětlete rozdíl mezi "ethical hacking" a kyberzločinem |
|||
- Toto je edukační prostředí |
|||
|
|||
4. **Bezpečnostní myšlení:** |
|||
- Motivujte studenty myslet jako útočníci |
|||
- "Jak bych tohle mohl zneužít?" |
|||
- Pak myslet jako obránci: "Jak tomu zabráním?" |
|||
|
|||
### Časté dotazy studentů: |
|||
|
|||
**Q: "Kde se s XSS můžu setkat?"** |
|||
A: Všude kde je formulář: komentáře, profily, vyhledávání, chat, recenze... |
|||
|
|||
**Q: "Proč vývojáři dělají takové chyby?"** |
|||
A: Někdy neznají rizika, někdy spěchají, někdy zapomenou ošetřit vstup. |
|||
|
|||
**Q: "Je to jediná bezpečnostní hrozba?"** |
|||
A: Ne! Existuje SQL injection, CSRF, clickjacking, a mnoho dalších. Bezpečnost je obrovské téma. |
|||
|
|||
**Q: "Stačí použít `textContent` a jsem v bezpečí?"** |
|||
A: Je to dobrý start, ale bezpečnost má mnoho vrstev. Na serveru musíte data také validovat! |
|||
|
|||
**Q: "Můžu takhle hacknout Facebook?"** |
|||
A: Ne! Velké firmy mají security týmy. A bylo by to TRESTNÉ! Nikdy to nezkoušejte bez povolení. |
|||
|
|||
## 🔗 Další studium |
|||
|
|||
### Pro zvídavé studenty doporučte: |
|||
|
|||
1. **OWASP Top 10** - seznam nejčastějších bezpečnostních hrozeb |
|||
2. **PortSwigger Web Security Academy** - zdarma kurzy o web security |
|||
3. **HackTheBox** - legální hackování (s povolením) |
|||
4. **Bug Bounty programy** - etické hackování za peníze |
|||
|
|||
### Užitečné nástroje: |
|||
|
|||
- **Browser DevTools (F12)** - konzole, network, elements |
|||
- **Burp Suite** - testování web aplikací |
|||
- **ZAP (Zed Attack Proxy)** - open-source security scanner |
|||
|
|||
## 📝 Domácí úkol (nepovinné) |
|||
|
|||
**Zadání:** |
|||
Vytvořte vlastní mini webovou aplikaci (např. TODO list nebo chat) s těmito požadavky: |
|||
|
|||
1. Formulář pro přidání položky |
|||
2. Zobrazení položek na stránce |
|||
3. **Implementujte to BEZPEČNĚ** (použijte `textContent`) |
|||
4. V komentářích vysvětlete, proč je to bezpečné |
|||
5. Zkuste to "hacknout" - mělo by to selhat! |
|||
|
|||
**Bonus:** |
|||
Vytvořte také zranitelnou verzi a ukažte rozdíl. |
|||
|
|||
## ✅ Co by studenti měli umět po lekci |
|||
|
|||
Po této lekci by studenti měli: |
|||
|
|||
✅ Vědět co je XSS (Cross-Site Scripting) |
|||
✅ Umět vysvětlit proč je `innerHTML` nebezpečné |
|||
✅ Znát rozdíl mezi `innerHTML` a `textContent` |
|||
✅ Umět použít `createElement()` pro tvorbu DOM elementů |
|||
✅ Znát pravidlo "DON'T TRUST THE INPUT" |
|||
✅ Chápat proč je bezpečnost webů důležitá |
|||
✅ Vědět, že hacking bez povolení je trestný čin |
|||
✅ Mít základní bezpečnostní mindset při vývoji webů |
|||
|
|||
## 🚨 Důležité poznámky |
|||
|
|||
### Pro učitele: |
|||
|
|||
1. **Tato lekce obsahuje funkční XSS exploity** |
|||
- Soubory jsou jen pro vzdělávací účely |
|||
- Nikdy je nenahrajte na veřejný server |
|||
- Nesdílejte je mimo bezpečné prostředí |
|||
|
|||
2. **Etika a zákon:** |
|||
- Vysvětlete studentům, že: |
|||
- Hacking bez povolení = trestný čin |
|||
- V ČR: Zákon č. 40/2009 Sb. trestní zákoník, § 230 |
|||
- Hrozí až 3 roky vězení |
|||
- Ethical hacking se dělá POUZE s písemným povolením |
|||
|
|||
3. **Zodpovědnost:** |
|||
- Zdůrazněte odpovědnost vývojářů |
|||
- "Se schopností přichází odpovědnost" |
|||
- Vývojáři chrání data a soukromí uživatelů |
|||
|
|||
## 🎉 Závěr |
|||
|
|||
Tato lekce poskytuje studentům **praktickou zkušenost s bezpečnostní zranitelností** v kontrolovaném prostředí. Je to jeden z nejlepších způsobů, jak naučit důležitost bezpečného programování. |
|||
|
|||
**Klíčové sdělení:** |
|||
``` |
|||
🔐 BEZPEČNOST NENÍ VOLITELNÁ! |
|||
🔐 VŽDY OŠETŘUJTE VSTUP! |
|||
🔐 DON'T TRUST THE INPUT! |
|||
``` |
|||
|
|||
--- |
|||
|
|||
Vytvořeno: 2. prosince 2025 |
|||
Předmět: Webové Technologie (WTL) |
|||
Cílová skupina: 3. ročník IT |
|||
Téma: Bezpečnost webových aplikací - XSS |
|||
|
|||
**Hodně úspěchů při výuce! 🛡️** |
|||
@ -0,0 +1,157 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Návštěvní kniha - BEZPEČNÁ ✅</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
</head> |
|||
<body class="bg-light p-4"> |
|||
<div class="container"> |
|||
<!-- BEZPEČNOST --> |
|||
<div class="alert alert-success"> |
|||
<h3>✅ BEZPEČNÁ VERZE - nelze hacknout!</h3> |
|||
<p>Používá <code>textContent</code> - SPRÁVNĚ!</p> |
|||
</div> |
|||
|
|||
<div class="row"> |
|||
<!-- FORMULÁŘ --> |
|||
<div class="col-md-6"> |
|||
<div class="card"> |
|||
<div class="card-header bg-success text-white"> |
|||
<h3>📖 Návštěvní kniha</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<form id="myForm"> |
|||
<div class="mb-3"> |
|||
<label class="form-label">Jméno:</label> |
|||
<input type="text" class="form-control" id="name"> |
|||
</div> |
|||
<div class="mb-3"> |
|||
<label class="form-label">Zpráva:</label> |
|||
<textarea class="form-control" id="message" rows="3"></textarea> |
|||
</div> |
|||
<button type="submit" class="btn btn-success">Přidat záznam</button> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ZKUSTE HACKNOUT --> |
|||
<div class="col-md-6"> |
|||
<div class="card border-success"> |
|||
<div class="card-header bg-dark text-white"> |
|||
<h4>🛡️ Zkuste to hacknout!</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<h5>Zkuste stejné "útoky":</h5> |
|||
|
|||
<div class="alert alert-secondary"> |
|||
<strong>1. Alert:</strong> |
|||
<pre><code><script>alert('HACKNUTÝ!')</script></code></pre> |
|||
<small class="text-success">✅ Nefunguje!</small> |
|||
</div> |
|||
|
|||
<div class="alert alert-secondary"> |
|||
<strong>2. HTML:</strong> |
|||
<pre><code><h1>HACKED!</h1></code></pre> |
|||
<small class="text-success">✅ Zobrazí se jako text!</small> |
|||
</div> |
|||
|
|||
<div class="alert alert-info"> |
|||
<strong>💡 Výsledek:</strong><br> |
|||
Vše se zobrazí jako TEXT, ne jako KÓD! |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ZÁZNAMY --> |
|||
<div class="card mt-4"> |
|||
<div class="card-header bg-success text-white"> |
|||
<h4>📝 Záznamy</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<div id="entries"> |
|||
<p class="text-muted">Zatím žádné záznamy...</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- VYSVĚTLENÍ --> |
|||
<div class="card mt-4 border-success"> |
|||
<div class="card-header bg-success text-white"> |
|||
<h4>🔍 Bezpečný kód:</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<pre class="bg-light p-3"><code>// ✅ BEZPEČNÉ! |
|||
const div = document.createElement('div'); |
|||
const strong = document.createElement('strong'); |
|||
const text = document.createElement('span'); |
|||
|
|||
strong.textContent = name; // ✅ textContent = BEZPEČNÉ |
|||
text.textContent = ': ' + message; // ✅ textContent = BEZPEČNÉ |
|||
|
|||
div.appendChild(strong); |
|||
div.appendChild(text); |
|||
entriesDiv.appendChild(div);</code></pre> |
|||
<div class="alert alert-success mt-3"> |
|||
<strong>Proč je to bezpečné?</strong><br> |
|||
<code>textContent</code> zobrazí vše jako ČISTÝ TEXT.<br> |
|||
HTML a JavaScript se NIKDY nespustí! |
|||
</div> |
|||
|
|||
<h5 class="mt-4">📊 Porovnání:</h5> |
|||
<table class="table table-bordered"> |
|||
<tr class="table-danger"> |
|||
<td><code>innerHTML</code></td> |
|||
<td>❌ NEBEZPEČNÉ</td> |
|||
<td>Spustí kód</td> |
|||
</tr> |
|||
<tr class="table-success"> |
|||
<td><code>textContent</code></td> |
|||
<td>✅ BEZPEČNÉ</td> |
|||
<td>Jen text</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
// ===== BEZPEČNÝ KÓD ===== |
|||
|
|||
const form = document.getElementById('myForm'); |
|||
const entriesDiv = document.getElementById('entries'); |
|||
|
|||
form.addEventListener('submit', function(e) { |
|||
e.preventDefault(); // Zastaví odeslání formuláře |
|||
|
|||
// Získáme data |
|||
const name = document.getElementById('name').value; |
|||
const message = document.getElementById('message').value; |
|||
|
|||
// ✅ BEZPEČNÉ: Vytvoříme elementy |
|||
const div = document.createElement('div'); |
|||
div.className = 'alert alert-info'; |
|||
|
|||
const strong = document.createElement('strong'); |
|||
strong.textContent = name; // ✅ textContent je BEZPEČNÉ! |
|||
|
|||
const text = document.createElement('span'); |
|||
text.textContent = ': ' + message; // ✅ textContent je BEZPEČNÉ! |
|||
|
|||
// Složíme dohromady |
|||
div.appendChild(strong); |
|||
div.appendChild(text); |
|||
|
|||
// Přidáme na stránku |
|||
entriesDiv.appendChild(div); |
|||
|
|||
// Resetujeme formulář |
|||
form.reset(); |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,335 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Návštěvní kniha - BEZPEČNÁ VERZE ✅</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
<style> |
|||
.entry { |
|||
border-left: 4px solid #198754; |
|||
transition: all 0.3s; |
|||
} |
|||
.entry:hover { |
|||
background-color: #f8f9fa; |
|||
transform: translateX(5px); |
|||
} |
|||
.safe-banner { |
|||
background: linear-gradient(135deg, #198754 0%, #146c43 100%); |
|||
color: white; |
|||
padding: 20px; |
|||
margin-bottom: 30px; |
|||
border-radius: 10px; |
|||
box-shadow: 0 4px 6px rgba(25, 135, 84, 0.3); |
|||
} |
|||
</style> |
|||
</head> |
|||
<body class="bg-light"> |
|||
<!-- BEZPEČNOST BANNER --> |
|||
<div class="container mt-4"> |
|||
<div class="safe-banner"> |
|||
<h2>✅ BEZPEČNÁ VERZE ✅</h2> |
|||
<p class="mb-0"> |
|||
<strong>Tato verze je BEZPEČNÁ!</strong> Používá <code>textContent</code> a správně ošetřuje vstup. |
|||
XSS útoky zde NEFUNGUJÍ. |
|||
</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="container"> |
|||
<div class="row"> |
|||
<!-- LEVÝ SLOUPEC - Formulář --> |
|||
<div class="col-md-6"> |
|||
<div class="card shadow-sm"> |
|||
<div class="card-header bg-success text-white"> |
|||
<h3 class="mb-0">📖 Návštěvní kniha</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<form id="guestbookForm"> |
|||
<div class="mb-3"> |
|||
<label for="name" class="form-label">Vaše jméno:</label> |
|||
<input type="text" class="form-control" id="name" required> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="message" class="form-label">Zpráva:</label> |
|||
<textarea class="form-control" id="message" rows="4" required></textarea> |
|||
<div class="form-text">Napište nám, co si myslíte...</div> |
|||
</div> |
|||
|
|||
<button type="submit" class="btn btn-success w-100"> |
|||
💾 Přidat záznam |
|||
</button> |
|||
</form> |
|||
|
|||
<div class="alert alert-success mt-3"> |
|||
<small> |
|||
<strong>🔒 Tento formulář je BEZPEČNÝ!</strong><br> |
|||
Zkuste zadat HTML nebo JavaScript - nezpůsobí to nic nebezpečného. |
|||
</small> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- PRAVÝ SLOUPEC - Zkuste to hacknout (nebude fungovat) --> |
|||
<div class="col-md-6"> |
|||
<div class="card shadow-sm border-success"> |
|||
<div class="card-header bg-dark text-white"> |
|||
<h4 class="mb-0">🛡️ Zkuste to hacknout!</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<h5>Zkuste tyto "útoky" (nebudou fungovat):</h5> |
|||
|
|||
<div class="alert alert-secondary"> |
|||
<strong>1. Alert:</strong> |
|||
<pre class="mb-0"><code><script>alert('Pokus o útok')</script></code></pre> |
|||
<small class="text-success">✅ Zobrazí se jako text, nespustí se!</small> |
|||
</div> |
|||
|
|||
<div class="alert alert-secondary"> |
|||
<strong>2. HTML:</strong> |
|||
<pre class="mb-0"><code><h1 style="color:red">HACKED!</h1></code></pre> |
|||
<small class="text-success">✅ Zobrazí se jako text!</small> |
|||
</div> |
|||
|
|||
<div class="alert alert-secondary"> |
|||
<strong>3. Obrázek:</strong> |
|||
<pre class="mb-0"><code><img src=x onerror="alert('XSS')"></code></pre> |
|||
<small class="text-success">✅ Nespustí se JavaScript!</small> |
|||
</div> |
|||
|
|||
<div class="alert alert-info mt-3"> |
|||
<strong>💡 Výsledek:</strong><br> |
|||
Veškerý HTML kód se zobrazí jako obyčejný text, nespustí se! |
|||
Stránka je v bezpečí. 🛡️ |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ZÁZNAMY --> |
|||
<div class="row mt-4"> |
|||
<div class="col-12"> |
|||
<div class="card shadow-sm"> |
|||
<div class="card-header bg-success text-white d-flex justify-content-between align-items-center"> |
|||
<h4 class="mb-0">📝 Záznamy návštěvníků</h4> |
|||
<button class="btn btn-sm btn-light" onclick="clearEntries()">🗑️ Smazat vše</button> |
|||
</div> |
|||
<div class="card-body"> |
|||
<div id="entries"> |
|||
<div class="alert alert-info"> |
|||
<em>Zatím žádné záznamy. Buďte první!</em> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- VYSVĚTLENÍ --> |
|||
<div class="row mt-4 mb-4"> |
|||
<div class="col-12"> |
|||
<div class="card border-success"> |
|||
<div class="card-header bg-success text-white"> |
|||
<h4 class="mb-0">🔍 Jak to funguje? (BEZPEČNÝ KÓD)</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<h5>Bezpečný kód v JavaScriptu:</h5> |
|||
<pre class="bg-light p-3 rounded"><code>// ✅ BEZPEČNÉ - používá createElement a textContent! |
|||
|
|||
// 1. Vytvoříme elementy pomocí createElement (ne innerHTML!) |
|||
const entryDiv = document.createElement('div'); |
|||
entryDiv.className = 'entry mb-3 p-3 bg-white rounded shadow-sm'; |
|||
|
|||
const nameStrong = document.createElement('strong'); |
|||
nameStrong.style.color = '#198754'; |
|||
nameStrong.style.fontSize = '1.1em'; |
|||
|
|||
// 2. Nastavíme text pomocí textContent (ne innerHTML!) |
|||
nameStrong.textContent = '👤 ' + name; // ✅ BEZPEČNÉ |
|||
|
|||
const messagePara = document.createElement('p'); |
|||
messagePara.textContent = message; // ✅ BEZPEČNÉ |
|||
|
|||
// 3. Přidáme do stránky |
|||
entryDiv.appendChild(nameStrong); |
|||
entryDiv.appendChild(messagePara); |
|||
entriesDiv.insertBefore(entryDiv, entriesDiv.firstChild);</code></pre> |
|||
|
|||
<div class="alert alert-success mt-3"> |
|||
<strong>✅ Proč je to bezpečné?</strong> |
|||
<ul class="mb-0"> |
|||
<li><code>textContent</code> vždy vkládá čistý TEXT, ne HTML</li> |
|||
<li><code>createElement()</code> vytváří čisté DOM elementy</li> |
|||
<li>Jakýkoliv <code><script></code> nebo <code><img></code> tag se zobrazí jako text</li> |
|||
<li>JavaScript kód se NIKDY nespustí</li> |
|||
<li>Stránka je chráněná před XSS útoky</li> |
|||
</ul> |
|||
</div> |
|||
|
|||
<h5 class="mt-4">📚 Pravidlo #1 bezpečnosti:</h5> |
|||
<div class="alert alert-warning"> |
|||
<h4 class="alert-heading">🚨 "DON'T TRUST THE INPUT"</h4> |
|||
<p><strong>NIKDY nedůvěřujte vstupu od uživatele!</strong></p> |
|||
<ul class="mb-0"> |
|||
<li>Vždy ošetřujte vstup</li> |
|||
<li>Používejte <code>textContent</code> místo <code>innerHTML</code></li> |
|||
<li>Validujte data na serveru i klientu</li> |
|||
<li>Escapujte speciální znaky</li> |
|||
</ul> |
|||
</div> |
|||
|
|||
<h5 class="mt-4">Porovnání:</h5> |
|||
<table class="table table-bordered"> |
|||
<thead class="table-dark"> |
|||
<tr> |
|||
<th>Metoda</th> |
|||
<th>Bezpečnost</th> |
|||
<th>Použití</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr class="table-danger"> |
|||
<td><code>innerHTML</code></td> |
|||
<td>❌ NEBEZPEČNÉ</td> |
|||
<td>Spustí HTML a JavaScript</td> |
|||
</tr> |
|||
<tr class="table-success"> |
|||
<td><code>textContent</code></td> |
|||
<td>✅ BEZPEČNÉ</td> |
|||
<td>Vloží jen čistý text</td> |
|||
</tr> |
|||
<tr class="table-success"> |
|||
<td><code>createElement()</code></td> |
|||
<td>✅ BEZPEČNÉ</td> |
|||
<td>Vytvoří čistý DOM element</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script src="js/bootstrap.bundle.js"></script> |
|||
<script> |
|||
// ===== BEZPEČNÝ KÓD - POUŽÍVEJTE TOTO! ===== |
|||
|
|||
const form = document.getElementById('guestbookForm'); |
|||
const entriesDiv = document.getElementById('entries'); |
|||
|
|||
// Načteme záznamy z localStorage při načtení stránky |
|||
loadEntries(); |
|||
|
|||
form.addEventListener('submit', function(e) { |
|||
e.preventDefault(); |
|||
|
|||
// Získáme data z formuláře |
|||
const name = document.getElementById('name').value; |
|||
const message = document.getElementById('message').value; |
|||
|
|||
// ✅ BEZPEČNÉ: Vytvoříme elementy pomocí DOM API |
|||
createEntry(name, message); |
|||
|
|||
// Uložíme do localStorage |
|||
saveEntry(name, message); |
|||
|
|||
// Resetujeme formulář |
|||
form.reset(); |
|||
}); |
|||
|
|||
function createEntry(name, message) { |
|||
// Smažeme "žádné záznamy" zprávu pokud existuje |
|||
const emptyAlert = entriesDiv.querySelector('.alert-info'); |
|||
if (emptyAlert) { |
|||
emptyAlert.remove(); |
|||
} |
|||
|
|||
// ✅ KROK 1: Vytvoříme hlavní kontejner |
|||
const entryDiv = document.createElement('div'); |
|||
entryDiv.className = 'entry mb-3 p-3 bg-white rounded shadow-sm'; |
|||
|
|||
// ✅ KROK 2: Vytvoříme header s jménem a časem |
|||
const headerDiv = document.createElement('div'); |
|||
headerDiv.className = 'd-flex justify-content-between align-items-start'; |
|||
|
|||
const nameDiv = document.createElement('div'); |
|||
|
|||
const nameStrong = document.createElement('strong'); |
|||
nameStrong.style.color = '#198754'; |
|||
nameStrong.style.fontSize = '1.1em'; |
|||
nameStrong.textContent = '👤 ' + name; // ✅ textContent je BEZPEČNÉ! |
|||
|
|||
const timeSmall = document.createElement('small'); |
|||
timeSmall.className = 'text-muted ms-2'; |
|||
timeSmall.textContent = new Date().toLocaleString('cs-CZ'); |
|||
|
|||
nameDiv.appendChild(nameStrong); |
|||
nameDiv.appendChild(timeSmall); |
|||
headerDiv.appendChild(nameDiv); |
|||
|
|||
// ✅ KROK 3: Přidáme oddělovač |
|||
const hr = document.createElement('hr'); |
|||
|
|||
// ✅ KROK 4: Vytvoříme zprávu |
|||
const messagePara = document.createElement('p'); |
|||
messagePara.className = 'mb-0'; |
|||
messagePara.textContent = message; // ✅ textContent je BEZPEČNÉ! |
|||
|
|||
// ✅ KROK 5: Složíme vše dohromady |
|||
entryDiv.appendChild(headerDiv); |
|||
entryDiv.appendChild(hr); |
|||
entryDiv.appendChild(messagePara); |
|||
|
|||
// ✅ KROK 6: Přidáme na začátek seznamu |
|||
entriesDiv.insertBefore(entryDiv, entriesDiv.firstChild); |
|||
} |
|||
|
|||
function saveEntry(name, message) { |
|||
// Získáme existující záznamy |
|||
let entries = JSON.parse(localStorage.getItem('guestbook_safe') || '[]'); |
|||
|
|||
// Přidáme nový záznam |
|||
entries.unshift({ |
|||
name: name, |
|||
message: message, |
|||
timestamp: new Date().toISOString() |
|||
}); |
|||
|
|||
// Uložíme zpět |
|||
localStorage.setItem('guestbook_safe', JSON.stringify(entries)); |
|||
} |
|||
|
|||
function loadEntries() { |
|||
const entries = JSON.parse(localStorage.getItem('guestbook_safe') || '[]'); |
|||
|
|||
if (entries.length === 0) { |
|||
return; |
|||
} |
|||
|
|||
// Smažeme prázdnou zprávu |
|||
entriesDiv.innerHTML = ''; |
|||
|
|||
// ✅ Vytvoříme každý záznam BEZPEČNĚ |
|||
entries.forEach(entry => { |
|||
createEntry(entry.name, entry.message); |
|||
}); |
|||
} |
|||
|
|||
function clearEntries() { |
|||
if (confirm('Opravdu chcete smazat všechny záznamy?')) { |
|||
localStorage.removeItem('guestbook_safe'); |
|||
entriesDiv.innerHTML = '<div class="alert alert-info"><em>Zatím žádné záznamy. Buďte první!</em></div>'; |
|||
} |
|||
} |
|||
|
|||
// Info pro console |
|||
console.log('%c✅ BEZPEČNÁ VERZE ✅', 'color: green; font-size: 20px; font-weight: bold;'); |
|||
console.log('Tato stránka je CHRÁNĚNÁ před XSS útoky!'); |
|||
console.log('Používá textContent a createElement() místo innerHTML.'); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -0,0 +1,313 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>XSS Demo - Don't Trust The Input</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
<style> |
|||
.hero { |
|||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|||
color: white; |
|||
padding: 60px 0; |
|||
margin-bottom: 40px; |
|||
} |
|||
.version-card { |
|||
transition: transform 0.3s, box-shadow 0.3s; |
|||
height: 100%; |
|||
} |
|||
.version-card:hover { |
|||
transform: translateY(-5px); |
|||
box-shadow: 0 10px 20px rgba(0,0,0,0.2); |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<!-- HERO SEKCE --> |
|||
<div class="hero"> |
|||
<div class="container text-center"> |
|||
<h1 class="display-3 mb-3">🛡️ XSS Security Demo</h1> |
|||
<p class="lead">Lekce bezpečnosti: "Don't Trust The Input"</p> |
|||
<p class="fs-5">Porovnání zranitelné vs. bezpečné implementace formuláře</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="container mb-5"> |
|||
<!-- CO SE NAUČÍTE --> |
|||
<div class="row mb-5"> |
|||
<div class="col-12"> |
|||
<div class="card shadow"> |
|||
<div class="card-body"> |
|||
<h2 class="card-title">🎯 Co se v této lekci naučíte:</h2> |
|||
<div class="row mt-4"> |
|||
<div class="col-md-6"> |
|||
<ul class="list-unstyled"> |
|||
<li class="mb-2">✅ Co je XSS (Cross-Site Scripting) útok</li> |
|||
<li class="mb-2">✅ Jak funguje nebezpečný kód s <code>innerHTML</code></li> |
|||
<li class="mb-2">✅ Jak útočníci zneužívají formuláře</li> |
|||
<li class="mb-2">✅ Reálné příklady XSS útoků</li> |
|||
</ul> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<ul class="list-unstyled"> |
|||
<li class="mb-2">✅ Jak správně ošetřit vstup od uživatele</li> |
|||
<li class="mb-2">✅ Použití <code>textContent</code> místo <code>innerHTML</code></li> |
|||
<li class="mb-2">✅ Bezpečné vytváření DOM elementů</li> |
|||
<li class="mb-2">✅ Pravidlo "Don't Trust The Input"</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- POROVNÁNÍ VERZÍ --> |
|||
<h2 class="text-center mb-4">🔍 Vyberte verzi k testování:</h2> |
|||
|
|||
<div class="row g-4"> |
|||
<!-- ZRANITELNÁ VERZE --> |
|||
<div class="col-md-6"> |
|||
<div class="card version-card border-danger border-3"> |
|||
<div class="card-header bg-danger text-white text-center"> |
|||
<h3 class="mb-0">⚠️ ZRANITELNÁ VERZE</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<div class="text-center mb-3"> |
|||
<span class="badge bg-danger fs-5">NEBEZPEČNÁ</span> |
|||
</div> |
|||
|
|||
<h5>Co tato verze dělá ŠPATNĚ:</h5> |
|||
<ul> |
|||
<li>Používá <code>innerHTML</code></li> |
|||
<li>Neošetřuje vstup od uživatele</li> |
|||
<li>Spouští HTML a JavaScript kód</li> |
|||
<li>Je zranitelná vůči XSS útokům</li> |
|||
</ul> |
|||
|
|||
<div class="alert alert-danger"> |
|||
<strong>⚠️ Varování:</strong> Toto je ukázka jak <strong>NEDĚLAT</strong> webové aplikace! |
|||
</div> |
|||
|
|||
<h5 class="mt-3">Zkuste tyto útoky:</h5> |
|||
<div class="bg-light p-2 rounded mb-2"> |
|||
<code><script>alert('XSS')</script></code> |
|||
</div> |
|||
<div class="bg-light p-2 rounded mb-2"> |
|||
<code><h1>HACKED!</h1></code> |
|||
</div> |
|||
<div class="bg-light p-2 rounded"> |
|||
<code><img src=x onerror="alert('Útok')"></code> |
|||
</div> |
|||
|
|||
<div class="d-grid gap-2 mt-4"> |
|||
<a href="zranitelna_verze.html" class="btn btn-danger btn-lg"> |
|||
🔓 Otevřít zranitelnou verzi |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- BEZPEČNÁ VERZE --> |
|||
<div class="col-md-6"> |
|||
<div class="card version-card border-success border-3"> |
|||
<div class="card-header bg-success text-white text-center"> |
|||
<h3 class="mb-0">✅ BEZPEČNÁ VERZE</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<div class="text-center mb-3"> |
|||
<span class="badge bg-success fs-5">BEZPEČNÁ</span> |
|||
</div> |
|||
|
|||
<h5>Co tato verze dělá SPRÁVNĚ:</h5> |
|||
<ul> |
|||
<li>Používá <code>textContent</code></li> |
|||
<li>Používá <code>createElement()</code></li> |
|||
<li>Ošetřuje veškerý vstup</li> |
|||
<li>XSS útoky nefungují!</li> |
|||
</ul> |
|||
|
|||
<div class="alert alert-success"> |
|||
<strong>✅ Bezpečnost:</strong> Toto je správný způsob, jak psát bezpečné webové aplikace! |
|||
</div> |
|||
|
|||
<h5 class="mt-3">Zkuste "hacknout":</h5> |
|||
<div class="bg-light p-2 rounded mb-2"> |
|||
<code><script>alert('XSS')</script></code> |
|||
<span class="text-success">→ Zobrazí jako text ✅</span> |
|||
</div> |
|||
<div class="bg-light p-2 rounded mb-2"> |
|||
<code><h1>HACKED!</h1></code> |
|||
<span class="text-success">→ Zobrazí jako text ✅</span> |
|||
</div> |
|||
<div class="bg-light p-2 rounded"> |
|||
<code><img src=x onerror="alert('Útok')"></code> |
|||
<span class="text-success">→ Nespustí se ✅</span> |
|||
</div> |
|||
|
|||
<div class="d-grid gap-2 mt-4"> |
|||
<a href="bezpecna_verze.html" class="btn btn-success btn-lg"> |
|||
🔒 Otevřít bezpečnou verzi |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- CO JE XSS --> |
|||
<div class="row mt-5"> |
|||
<div class="col-12"> |
|||
<div class="card shadow"> |
|||
<div class="card-header bg-dark text-white"> |
|||
<h3 class="mb-0">🧠 Co je XSS (Cross-Site Scripting)?</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<p class="lead"> |
|||
XSS je bezpečnostní zranitelnost, která umožňuje útočníkovi vložit škodlivý kód |
|||
(obvykle JavaScript) do webové stránky. |
|||
</p> |
|||
|
|||
<div class="row mt-4"> |
|||
<div class="col-md-6"> |
|||
<h5>🔴 Co může útočník udělat:</h5> |
|||
<ul> |
|||
<li>Ukrást přihlašovací údaje (cookies, session)</li> |
|||
<li>Změnit obsah stránky</li> |
|||
<li>Přesměrovat na phishingovou stránku</li> |
|||
<li>Instalovat keylogger (zaznamenávat stisky kláves)</li> |
|||
<li>Spustit malware</li> |
|||
<li>Zneužít identitu uživatele</li> |
|||
</ul> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<h5>🛡️ Jak se bránit:</h5> |
|||
<ul> |
|||
<li><strong>Nikdy nedůvěřujte vstupu!</strong> (Don't Trust The Input)</li> |
|||
<li>Používejte <code>textContent</code> místo <code>innerHTML</code></li> |
|||
<li>Používejte <code>createElement()</code> pro DOM elementy</li> |
|||
<li>Validujte a sanitizujte vstup</li> |
|||
<li>Escapujte HTML entity</li> |
|||
<li>Používejte Content Security Policy (CSP)</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="alert alert-warning mt-4"> |
|||
<h5 class="alert-heading">⚡ Zlaté pravidlo bezpečnosti:</h5> |
|||
<p class="mb-0 fs-5"> |
|||
<strong>"DON'T TRUST THE INPUT"</strong> - Nikdy nedůvěřujte tomu, co uživatel zadá do formuláře! |
|||
</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- POSTUP LEKCE --> |
|||
<div class="row mt-5"> |
|||
<div class="col-12"> |
|||
<div class="card shadow border-primary"> |
|||
<div class="card-header bg-primary text-white"> |
|||
<h3 class="mb-0">📚 Doporučený postup lekce:</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<ol class="fs-5"> |
|||
<li class="mb-3"> |
|||
<strong>Krok 1:</strong> Nejdřív otevřete <span class="badge bg-danger">ZRANITELNOU VERZI</span> |
|||
<ul class="mt-2"> |
|||
<li>Vyzkoušejte si XSS útoky z pravého sloupce</li> |
|||
<li>Zkopírujte kód a vložte do formuláře</li> |
|||
<li>Pozorujte, co se stane!</li> |
|||
</ul> |
|||
</li> |
|||
<li class="mb-3"> |
|||
<strong>Krok 2:</strong> Prostudujte si kód ve spodní sekci "Co se děje pod kapotou" |
|||
<ul class="mt-2"> |
|||
<li>Pochopte proč je <code>innerHTML</code> nebezpečné</li> |
|||
<li>Podívejte se do konzole (F12)</li> |
|||
</ul> |
|||
</li> |
|||
<li class="mb-3"> |
|||
<strong>Krok 3:</strong> Otevřete <span class="badge bg-success">BEZPEČNOU VERZI</span> |
|||
<ul class="mt-2"> |
|||
<li>Zkuste stejné útoky - nebudou fungovat!</li> |
|||
<li>Pochopte rozdíl v přístupu</li> |
|||
</ul> |
|||
</li> |
|||
<li class="mb-3"> |
|||
<strong>Krok 4:</strong> Prostudujte si bezpečný kód |
|||
<ul class="mt-2"> |
|||
<li>Naučte se používat <code>textContent</code></li> |
|||
<li>Naučte se <code>createElement()</code></li> |
|||
</ul> |
|||
</li> |
|||
<li> |
|||
<strong>Krok 5:</strong> Zapamatujte si pravidlo <strong>"DON'T TRUST THE INPUT"</strong> |
|||
</li> |
|||
</ol> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- POROVNÁNÍ KÓDU --> |
|||
<div class="row mt-5 mb-5"> |
|||
<div class="col-12"> |
|||
<div class="card shadow"> |
|||
<div class="card-header bg-info text-white"> |
|||
<h3 class="mb-0">💻 Porovnání kódu</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-6"> |
|||
<h5 class="text-danger">❌ NEBEZPEČNÝ KÓD:</h5> |
|||
<pre class="bg-danger bg-opacity-10 p-3 rounded"><code>// ❌ ŠPATNĚ - innerHTML! |
|||
const html = ` |
|||
<div> |
|||
<strong>${name}</strong> |
|||
<p>${message}</p> |
|||
</div> |
|||
`; |
|||
element.innerHTML = html; |
|||
|
|||
// Pokud message obsahuje: |
|||
// <script>alert('XSS')</script> |
|||
// → SPUSTÍ SE!</code></pre> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<h5 class="text-success">✅ BEZPEČNÝ KÓD:</h5> |
|||
<pre class="bg-success bg-opacity-10 p-3 rounded"><code>// ✅ SPRÁVNĚ - createElement! |
|||
const div = document.createElement('div'); |
|||
|
|||
const strong = document.createElement('strong'); |
|||
strong.textContent = name; |
|||
|
|||
const p = document.createElement('p'); |
|||
p.textContent = message; |
|||
|
|||
div.appendChild(strong); |
|||
div.appendChild(p); |
|||
element.appendChild(div); |
|||
|
|||
// HTML kód se zobrazí jako TEXT |
|||
// → BEZPEČNÉ!</code></pre> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<footer class="bg-dark text-white py-4"> |
|||
<div class="container text-center"> |
|||
<p class="mb-0">🛡️ XSS Security Demo | WTL 2025 | Lekce 18a</p> |
|||
<p class="mb-0"><small>Remember: <strong>DON'T TRUST THE INPUT!</strong></small></p> |
|||
</div> |
|||
</footer> |
|||
|
|||
<script src="js/bootstrap.bundle.js"></script> |
|||
</body> |
|||
</html> |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -0,0 +1,154 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Návštěvní kniha - ZRANITELNÁ ⚠️</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
</head> |
|||
<body class="bg-light p-4"> |
|||
<div class="container"> |
|||
<!-- VAROVÁNÍ --> |
|||
<div class="alert alert-danger"> |
|||
<h3>⚠️ NEBEZPEČNÁ VERZE - lze hacknout!</h3> |
|||
<p>Používá <code>innerHTML</code> - ŠPATNĚ!</p> |
|||
</div> |
|||
|
|||
<div class="row"> |
|||
<!-- FORMULÁŘ --> |
|||
<div class="col-md-6"> |
|||
<div class="card"> |
|||
<div class="card-header bg-danger text-white"> |
|||
<h3>📖 Návštěvní kniha</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<form id="myForm"> |
|||
<div class="mb-3"> |
|||
<label class="form-label">Jméno:</label> |
|||
<input type="text" class="form-control" id="name"> |
|||
</div> |
|||
<div class="mb-3"> |
|||
<label class="form-label">Zpráva:</label> |
|||
<textarea class="form-control" id="message" rows="3"></textarea> |
|||
</div> |
|||
<button type="submit" class="btn btn-danger">Přidat záznam</button> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ÚTOKY --> |
|||
<div class="col-md-6"> |
|||
<div class="card border-danger"> |
|||
<div class="card-header bg-dark text-white"> |
|||
<h4>🎯 Zkuste tyto útoky:</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<h5>Do pole "Zpráva" zkopírujte:</h5> |
|||
|
|||
<div class="alert alert-success mb-2"> |
|||
<strong>✅ 1. IMG útok (FUNGUJE!):</strong> |
|||
<pre class="mb-0"><code><img src=x onerror="alert('HACKNUTÝ!')"></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-success mb-2"> |
|||
<strong>✅ 2. Změna pozadí (FUNGUJE!):</strong> |
|||
<pre class="mb-0"><code><img src=x onerror="document.body.style.background='red'"></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-success mb-2"> |
|||
<strong>✅ 3. Změna HTML (FUNGUJE!):</strong> |
|||
<pre class="mb-0"><code><h1 style="color:red; font-size:50px">HACKED!</h1></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-secondary mb-2"> |
|||
<strong>❌ 4. Script tag (NEFUNGUJE):</strong> |
|||
<pre class="mb-0"><code><script>alert('XSS')</script></code></pre> |
|||
<small class="text-muted">Prohlížeč blokuje script v innerHTML</small> |
|||
</div> |
|||
|
|||
<div class="alert alert-info"> |
|||
<strong>💡 Poznámka:</strong><br> |
|||
<code><script></code> v innerHTML nefunguje, ale <strong>event handlery ANO</strong>!<br> |
|||
Proto je innerHTML STÁLE nebezpečné! |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ZÁZNAMY --> |
|||
<div class="card mt-4"> |
|||
<div class="card-header bg-primary text-white"> |
|||
<h4>📝 Záznamy</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<div id="entries"> |
|||
<p class="text-muted">Zatím žádné záznamy...</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- VYSVĚTLENÍ --> |
|||
<div class="card mt-4 border-warning"> |
|||
<div class="card-header bg-warning"> |
|||
<h4>🔍 Problematický kód:</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<pre class="bg-light p-3"><code>// ❌ NEBEZPEČNÉ! |
|||
const html = `<p><strong>${name}</strong>: ${message}</p>`; |
|||
entriesDiv.innerHTML += html; // TADY JE PROBLÉM!</code></pre> |
|||
<div class="alert alert-danger mt-3 mb-0"> |
|||
<h5 class="alert-heading">⚠️ Proč je to nebezpečné?</h5> |
|||
<p><strong>innerHTML spustí HTML a event handlery!</strong></p> |
|||
|
|||
<h6 class="mt-3">❌ Nefunguje (prohlížeč blokuje):</h6> |
|||
<ul> |
|||
<li><code><script>alert(1)</script></code> - NESPUSTÍ SE</li> |
|||
</ul> |
|||
|
|||
<h6 class="mt-3">✅ Funguje (útočníci tohle používají!):</h6> |
|||
<ul class="mb-0"> |
|||
<li><code><img src=x onerror="alert(1)"></code> - SPUSTÍ SE!</li> |
|||
<li><code><body onload="alert(1)"></code> - SPUSTÍ SE!</li> |
|||
<li><code><svg onload="alert(1)"></code> - SPUSTÍ SE!</li> |
|||
<li><code><input onfocus="alert(1)" autofocus></code> - SPUSTÍ SE!</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
// ===== ZRANITELNÝ KÓD ===== |
|||
|
|||
const form = document.getElementById('myForm'); |
|||
const entriesDiv = document.getElementById('entries'); |
|||
|
|||
// Co dělá e.preventDefault()? |
|||
// → Zastaví normální chování formuláře (odeslání a reload stránky) |
|||
// → Abychom mohli zpracovat data sami přes JavaScript |
|||
|
|||
form.addEventListener('submit', function(e) { |
|||
e.preventDefault(); // Zastaví odeslání formuláře! |
|||
|
|||
// Získáme data |
|||
const name = document.getElementById('name').value; |
|||
const message = document.getElementById('message').value; |
|||
|
|||
// ❌ PROBLÉM: Vytvoříme HTML string |
|||
const html = ` |
|||
<div class="alert alert-info"> |
|||
<strong>${name}</strong>: ${message} |
|||
</div> |
|||
`; |
|||
|
|||
// ❌ KRITICKÝ PROBLÉM: innerHTML spustí JavaScript! |
|||
entriesDiv.innerHTML += html; |
|||
|
|||
// Resetujeme formulář |
|||
form.reset(); |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,273 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Návštěvní kniha - ZRANITELNÁ VERZE ⚠️</title> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
<style> |
|||
.entry { |
|||
border-left: 4px solid #0d6efd; |
|||
transition: all 0.3s; |
|||
} |
|||
.entry:hover { |
|||
background-color: #f8f9fa; |
|||
transform: translateX(5px); |
|||
} |
|||
.danger-banner { |
|||
background: linear-gradient(135deg, #dc3545 0%, #c82333 100%); |
|||
color: white; |
|||
padding: 20px; |
|||
margin-bottom: 30px; |
|||
border-radius: 10px; |
|||
box-shadow: 0 4px 6px rgba(220, 53, 69, 0.3); |
|||
} |
|||
</style> |
|||
</head> |
|||
<body class="bg-light"> |
|||
<!-- NEBEZPEČÍ BANNER --> |
|||
<div class="container mt-4"> |
|||
<div class="danger-banner"> |
|||
<h2>⚠️ VAROVÁNÍ: ZRANITELNÁ VERZE ⚠️</h2> |
|||
<p class="mb-0"> |
|||
<strong>Tato verze JE ZÁMĚRNĚ NEBEZPEČNÁ!</strong> Používá <code>innerHTML</code> bez ošetření vstupu. |
|||
Lze ji zneužít pomocí XSS (Cross-Site Scripting) útoku. |
|||
</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="container"> |
|||
<div class="row"> |
|||
<!-- LEVÝ SLOUPEC - Formulář --> |
|||
<div class="col-md-6"> |
|||
<div class="card shadow-sm"> |
|||
<div class="card-header bg-danger text-white"> |
|||
<h3 class="mb-0">📖 Návštěvní kniha</h3> |
|||
</div> |
|||
<div class="card-body"> |
|||
<form id="guestbookForm"> |
|||
<div class="mb-3"> |
|||
<label for="name" class="form-label">Vaše jméno:</label> |
|||
<input type="text" class="form-control" id="name" required> |
|||
</div> |
|||
|
|||
<div class="mb-3"> |
|||
<label for="message" class="form-label">Zpráva:</label> |
|||
<textarea class="form-control" id="message" rows="4" required></textarea> |
|||
<div class="form-text">Napište nám, co si myslíte...</div> |
|||
</div> |
|||
|
|||
<button type="submit" class="btn btn-danger w-100"> |
|||
💾 Přidat záznam |
|||
</button> |
|||
</form> |
|||
|
|||
<div class="alert alert-warning mt-3"> |
|||
<small> |
|||
<strong>🔓 Tento formulář NEOŠETŘUJE vstup!</strong><br> |
|||
Zkuste zadat HTML nebo JavaScript kód... |
|||
</small> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- PRAVÝ SLOUPEC - Nápověda pro hackování --> |
|||
<div class="col-md-6"> |
|||
<div class="card shadow-sm border-danger"> |
|||
<div class="card-header bg-dark text-white"> |
|||
<h4 class="mb-0">🎯 Návody na útoky</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<h5>Zkuste tyto XSS útoky:</h5> |
|||
|
|||
<div class="alert alert-danger"> |
|||
<strong>1. Jednoduchý alert:</strong> |
|||
<pre class="mb-0"><code><script>alert('Byl jsi hacknutý!')</script></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-danger"> |
|||
<strong>2. Změna stránky:</strong> |
|||
<pre class="mb-0"><code><h1 style="color:red">HACKED!</h1></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-danger"> |
|||
<strong>3. Obrázek s chybou:</strong> |
|||
<pre class="mb-0"><code><img src=x onerror="alert('XSS')"></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-danger"> |
|||
<strong>4. Krádež cookies:</strong> |
|||
<pre class="mb-0"><code><script>alert(document.cookie)</script></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-danger"> |
|||
<strong>5. Nekonečná smyčka:</strong> |
|||
<pre class="mb-0"><code><script>while(true){alert('SPAM')}</script></code></pre> |
|||
</div> |
|||
|
|||
<div class="alert alert-info mt-3"> |
|||
<strong>💡 Tip:</strong> Zkopírujte kód výše a vložte do formuláře! |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ZÁZNAMY --> |
|||
<div class="row mt-4"> |
|||
<div class="col-12"> |
|||
<div class="card shadow-sm"> |
|||
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center"> |
|||
<h4 class="mb-0">📝 Záznamy návštěvníků</h4> |
|||
<button class="btn btn-sm btn-light" onclick="clearEntries()">🗑️ Smazat vše</button> |
|||
</div> |
|||
<div class="card-body"> |
|||
<div id="entries"> |
|||
<div class="alert alert-info"> |
|||
<em>Zatím žádné záznamy. Buďte první!</em> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- VYSVĚTLENÍ --> |
|||
<div class="row mt-4 mb-4"> |
|||
<div class="col-12"> |
|||
<div class="card border-warning"> |
|||
<div class="card-header bg-warning"> |
|||
<h4 class="mb-0">🔍 Co se děje "pod kapotou"?</h4> |
|||
</div> |
|||
<div class="card-body"> |
|||
<h5>Problematický kód v JavaScriptu:</h5> |
|||
<pre class="bg-light p-3 rounded"><code>// ❌ NEBEZPEČNÉ - používá innerHTML! |
|||
const entryHTML = ` |
|||
<div class="entry mb-3 p-3 bg-white rounded"> |
|||
<strong>${name}</strong> |
|||
<p>${message}</p> |
|||
</div> |
|||
`; |
|||
entriesDiv.innerHTML += entryHTML; // PROBLÉM JE TADY!</code></pre> |
|||
|
|||
<div class="alert alert-danger mt-3"> |
|||
<strong>⚠️ Proč je to nebezpečné?</strong><br> |
|||
Když použijeme <code>innerHTML</code>, prohlížeč SPUSTÍ veškerý HTML a JavaScript kód, který uživatel zadá! |
|||
Útočník může: |
|||
<ul class="mb-0"> |
|||
<li>Spustit libovolný JavaScript</li> |
|||
<li>Ukrást cookies (přihlašovací údaje)</li> |
|||
<li>Změnit vzhled stránky</li> |
|||
<li>Přesměrovat na phishingovou stránku</li> |
|||
<li>Instalovat keylogger</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script src="js/bootstrap.bundle.js"></script> |
|||
<script> |
|||
// ===== ZRANITELNÝ KÓD - NEPOUŽÍVEJTE V PRODUKCI! ===== |
|||
|
|||
const form = document.getElementById('guestbookForm'); |
|||
const entriesDiv = document.getElementById('entries'); |
|||
|
|||
// Načteme záznamy z localStorage při načtení stránky |
|||
loadEntries(); |
|||
|
|||
form.addEventListener('submit', function(e) { |
|||
e.preventDefault(); |
|||
|
|||
// Získáme data z formuláře |
|||
const name = document.getElementById('name').value; |
|||
const message = document.getElementById('message').value; |
|||
|
|||
// ❌ PROBLÉM: Vytvoříme HTML pomocí template literálu |
|||
// Toto NEOŠETŘUJE uživatelský vstup! |
|||
const entryHTML = ` |
|||
<div class="entry mb-3 p-3 bg-white rounded shadow-sm"> |
|||
<div class="d-flex justify-content-between align-items-start"> |
|||
<div> |
|||
<strong style="color: #0d6efd; font-size: 1.1em;">👤 ${name}</strong> |
|||
<small class="text-muted ms-2">${new Date().toLocaleString('cs-CZ')}</small> |
|||
</div> |
|||
</div> |
|||
<hr> |
|||
<p class="mb-0">${message}</p> |
|||
</div> |
|||
`; |
|||
|
|||
// ❌ KRITICKÝ PROBLÉM: innerHTML spustí veškerý JavaScript! |
|||
if (entriesDiv.querySelector('.alert-info')) { |
|||
entriesDiv.innerHTML = ''; |
|||
} |
|||
entriesDiv.innerHTML = entryHTML + entriesDiv.innerHTML; |
|||
|
|||
// Uložíme do localStorage |
|||
saveEntry(name, message); |
|||
|
|||
// Resetujeme formulář |
|||
form.reset(); |
|||
}); |
|||
|
|||
function saveEntry(name, message) { |
|||
// Získáme existující záznamy |
|||
let entries = JSON.parse(localStorage.getItem('guestbook_vulnerable') || '[]'); |
|||
|
|||
// Přidáme nový záznam |
|||
entries.unshift({ |
|||
name: name, |
|||
message: message, |
|||
timestamp: new Date().toISOString() |
|||
}); |
|||
|
|||
// Uložíme zpět |
|||
localStorage.setItem('guestbook_vulnerable', JSON.stringify(entries)); |
|||
} |
|||
|
|||
function loadEntries() { |
|||
const entries = JSON.parse(localStorage.getItem('guestbook_vulnerable') || '[]'); |
|||
|
|||
if (entries.length === 0) { |
|||
return; |
|||
} |
|||
|
|||
entriesDiv.innerHTML = ''; |
|||
|
|||
entries.forEach(entry => { |
|||
// ❌ Opět používáme innerHTML - NEBEZPEČNÉ! |
|||
const entryHTML = ` |
|||
<div class="entry mb-3 p-3 bg-white rounded shadow-sm"> |
|||
<div class="d-flex justify-content-between align-items-start"> |
|||
<div> |
|||
<strong style="color: #0d6efd; font-size: 1.1em;">👤 ${entry.name}</strong> |
|||
<small class="text-muted ms-2">${new Date(entry.timestamp).toLocaleString('cs-CZ')}</small> |
|||
</div> |
|||
</div> |
|||
<hr> |
|||
<p class="mb-0">${entry.message}</p> |
|||
</div> |
|||
`; |
|||
entriesDiv.innerHTML += entryHTML; |
|||
}); |
|||
} |
|||
|
|||
function clearEntries() { |
|||
if (confirm('Opravdu chcete smazat všechny záznamy?')) { |
|||
localStorage.removeItem('guestbook_vulnerable'); |
|||
entriesDiv.innerHTML = '<div class="alert alert-info"><em>Zatím žádné záznamy. Buďte první!</em></div>'; |
|||
} |
|||
} |
|||
|
|||
// BONUS: Ukázka co útočník může udělat |
|||
// (Toto je jen pro demonstraci - v reálném útoku by to bylo skryté) |
|||
console.log('%c⚠️ BEZPEČNOSTNÍ VAROVÁNÍ ⚠️', 'color: red; font-size: 20px; font-weight: bold;'); |
|||
console.log('Tato stránka je ZRANITELNÁ vůči XSS útokům!'); |
|||
console.log('Zkuste zadat do formuláře: <script>alert("XSS útok!")</script>'); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,249 @@ |
|||
# 🤖 AI Projekty - Příprava na Bootstrap |
|||
|
|||
Tyto projekty byly vytvořeny pro důkladné procvičení HTML, CSS a JavaScript konceptů před začátkem práce s Bootstrap frameworkem. |
|||
|
|||
## 📋 Přehled projektů |
|||
|
|||
### 🎨 AI 01 - CSS Grid & Responzivní Layout |
|||
**Složitost:** ⭐⭐ Střední |
|||
**Čas:** 45-60 minut |
|||
**Zaměření:** CSS Grid, pokročilé selektory, media queries |
|||
|
|||
**Co se naučíte:** |
|||
- CSS Grid (grid-template-columns, gap) |
|||
- nth-child, first-child, last-child selektory |
|||
- Responzivní design s media queries |
|||
- CSS transformace při hover |
|||
|
|||
**Soubory:** |
|||
- `ai_01_grid_responsive/ZADANI.md` - Detailní zadání |
|||
- `ai_01_grid_responsive/index.html` - Startovací HTML |
|||
- `ai_01_grid_responsive/style.css` - CSS šablona |
|||
- `ai_01_grid_responsive/reseni.html` - Kompletní řešení |
|||
- `ai_01_grid_responsive/reseni.css` - CSS řešení s komentáři |
|||
|
|||
--- |
|||
|
|||
### 🏗️ AI 02 - Sémantické HTML5 & CSS Positioning |
|||
**Složitost:** ⭐⭐⭐ Náročné |
|||
**Čas:** 60-90 minut |
|||
**Zaměření:** Sémantické elementy, positioning, jednotky |
|||
|
|||
**Co se naučíte:** |
|||
- HTML5 sémantické elementy (nav, main, section, article, aside) |
|||
- Position: fixed, sticky, relative, absolute |
|||
- CSS jednotky: rem, em, vh, vw |
|||
- Strukturu moderní webové stránky |
|||
|
|||
**Soubory:** |
|||
- `ai_02_semantic_portfolio/ZADANI.md` |
|||
- `ai_02_semantic_portfolio/index.html` |
|||
- `ai_02_semantic_portfolio/style.css` |
|||
- `ai_02_semantic_portfolio/reseni.html` |
|||
- `ai_02_semantic_portfolio/reseni.css` |
|||
|
|||
--- |
|||
|
|||
### ✅ AI 03 - Pokročilá Validace Formulářů |
|||
**Složitost:** ⭐⭐⭐ Náročné |
|||
**Čas:** 90-120 minut |
|||
**Zaměření:** JavaScript validace, event handling, RegEx |
|||
|
|||
**Co se naučíte:** |
|||
- addEventListener vs inline events |
|||
- Form validation s JavaScriptem |
|||
- Regulární výrazy (RegEx) |
|||
- DOM manipulace (classList, innerHTML) |
|||
- Real-time validace s visual feedbackem |
|||
|
|||
**Soubory:** |
|||
- `ai_03_form_validation/ZADANI.md` |
|||
- `ai_03_form_validation/index.html` |
|||
- `ai_03_form_validation/style.css` |
|||
- `ai_03_form_validation/script.js` |
|||
- `ai_03_form_validation/reseni.html` |
|||
- `ai_03_form_validation/reseni.css` |
|||
- `ai_03_form_validation/reseni.js` |
|||
|
|||
--- |
|||
|
|||
### 🚀 AI 04 - Komplexní Bootstrap Prep Projekt |
|||
**Složitost:** ⭐⭐⭐⭐ Velmi náročné |
|||
**Čas:** 4-6 hodin |
|||
**Zaměření:** Komplexní projekt kombinující VŠE |
|||
|
|||
**Co se naučíte:** |
|||
- Všechny předchozí koncepty dohromady |
|||
- CSS proměnné (custom properties) |
|||
- Pokročilé animace |
|||
- Scroll efekty |
|||
- Modal okna, accordions |
|||
- Mobile-first přístup |
|||
|
|||
**Soubory:** |
|||
- `ai_04_prep_bootstrap/ZADANI.md` - Komplexní zadání |
|||
- `ai_04_prep_bootstrap/index.html` |
|||
- `ai_04_prep_bootstrap/css/style.css` |
|||
- `ai_04_prep_bootstrap/css/animations.css` |
|||
- `ai_04_prep_bootstrap/js/main.js` |
|||
- `ai_04_prep_bootstrap/js/validation.js` |
|||
- `ai_04_prep_bootstrap/js/scroll.js` |
|||
- `ai_04_prep_bootstrap/RESENI_PRIKLAD.md` - Tips & příklady |
|||
|
|||
--- |
|||
|
|||
## 🎯 Doporučený postup |
|||
|
|||
### Týden 1: |
|||
- **Den 1-2:** AI 01 - CSS Grid (+ opakování Grid konceptů) |
|||
- **Den 3-4:** AI 02 - Sémantika & Positioning (+ opakování HTML5) |
|||
|
|||
### Týden 2: |
|||
- **Den 1-3:** AI 03 - Validace formulářů (+ opakování JavaScript) |
|||
- **Den 4-5:** Příprava na AI 04 (zopakovat vše) |
|||
|
|||
### Týden 3: |
|||
- **Celý týden:** AI 04 - Komplexní projekt |
|||
- **Prezentace:** Konec týdne |
|||
|
|||
### Týden 4: |
|||
- **Začátek Bootstrap!** 🎉 |
|||
|
|||
--- |
|||
|
|||
## 📚 Co budete znát po dokončení všech projektů |
|||
|
|||
### HTML: |
|||
✅ Sémantické HTML5 elementy |
|||
✅ Formuláře a jejich atributy |
|||
✅ Správná struktura dokumentu |
|||
✅ Accessibility best practices |
|||
|
|||
### CSS: |
|||
✅ CSS Grid systém |
|||
✅ Flexbox |
|||
✅ Positioning (všechny typy) |
|||
✅ Media queries & responzivita |
|||
✅ CSS proměnné |
|||
✅ Jednotky (rem, em, vh, vw) |
|||
✅ Pseudo-třídy a pseudo-elementy |
|||
✅ Animations & transitions |
|||
✅ Gradienty, shadows, filters |
|||
|
|||
### JavaScript: |
|||
✅ DOM manipulace |
|||
✅ Event handling (addEventListener) |
|||
✅ Form validation |
|||
✅ Podmínky a cykly |
|||
✅ Funkce (function declaration, arrow functions) |
|||
✅ Regulární výrazy (RegEx) |
|||
✅ Práce s objekty a poli |
|||
|
|||
--- |
|||
|
|||
## 🔍 Proč tyto projekty před Bootstrapem? |
|||
|
|||
Bootstrap je mocný framework, ale bez pochopení základních konceptů můžete: |
|||
- Neumět framework přizpůsobit svým potřebám |
|||
- Vytvářet neefektivní kód |
|||
- Záviset na frameworku místo pochopení problému |
|||
- Mít problém při debugování |
|||
|
|||
**Po těchto projektech budete:** |
|||
- Rozumět, co Bootstrap dělá "pod kapotou" |
|||
- Umět rozhodnout, kdy Bootstrap použít a kdy ne |
|||
- Efektivně přizpůsobovat Bootstrap komponenty |
|||
- Psát lepší a čistší kód |
|||
|
|||
--- |
|||
|
|||
## 💡 Tips pro studenty |
|||
|
|||
### Při řešení projektů: |
|||
1. **Nejdřív HTML struktura** - Vždy začněte správnou HTML strukturou |
|||
2. **Pak mobile styling** - CSS začněte od mobile verzí (mobile-first) |
|||
3. **JavaScript na konec** - Interaktivitu přidávejte, když máte hotové HTML & CSS |
|||
4. **Časté testování** - Testujte často v browseru, nečekejte na konec |
|||
5. **Developer tools** - Používejte Chrome DevTools (F12) pro debugování |
|||
6. **Commit často** - Pokud používáte Git, commitujte po každé sekci |
|||
|
|||
### Užitečné VS Code extensions: |
|||
- Live Server - pro live reload |
|||
- Prettier - pro formátování kódu |
|||
- Auto Rename Tag - automatické přejmenování párových tagů |
|||
- CSS Peek - rychlý náhled CSS definic |
|||
|
|||
### Keyboard shortcuts: |
|||
- `Ctrl + /` - zakomentovat/odkomentovat |
|||
- `Alt + Shift + F` - formátovat dokument |
|||
- `Ctrl + D` - vybrat další výskyt slova |
|||
- `Alt + Up/Down` - přesunout řádek nahoru/dolů |
|||
|
|||
--- |
|||
|
|||
## 🆘 Když si nevíte rady |
|||
|
|||
1. **Přečtěte si zadání znovu** - Často je odpověď v zadání |
|||
2. **Podívejte se na předchozí lekce** - V `01_uvod` až `11_json` najdete příklady |
|||
3. **Použijte console.log()** - Pro debugging JavaScriptu |
|||
4. **Zkontrolujte Developer Tools** - Konzole často ukazuje chyby |
|||
5. **Postupujte po malých krocích** - Neřešte vše najednou |
|||
6. **Koukněte na reseni.html/css/js** - Ale zkuste to sami nejdřív! |
|||
|
|||
--- |
|||
|
|||
## 📊 Self-assessment checklist |
|||
|
|||
Po dokončení všech projektů byste měli umět odpovědět ANO na tyto otázky: |
|||
|
|||
### HTML: |
|||
- [ ] Znám rozdíl mezi `<div>` a sémantickými elementy? |
|||
- [ ] Umím vytvořit správnou strukturu formuláře? |
|||
- [ ] Vím, kdy použít `<section>`, `<article>`, `<aside>`? |
|||
|
|||
### CSS: |
|||
- [ ] Rozumím rozdílu mezi Grid a Flexbox? |
|||
- [ ] Umím vytvořit responzivní layout bez frameworku? |
|||
- [ ] Znám všechny typy positioningu a kdy je použít? |
|||
- [ ] Umím pracovat s rem, em jednotkami? |
|||
- [ ] Vím, jak fungují media queries? |
|||
|
|||
### JavaScript: |
|||
- [ ] Umím validovat formulář pomocí JavaScriptu? |
|||
- [ ] Rozumím event listenerům? |
|||
- [ ] Umím manipulovat s DOM? |
|||
- [ ] Znám základy RegEx? |
|||
- [ ] Umím vytvořit jednoduchou interaktivitu? |
|||
|
|||
**Pokud máte většinu zaškrtlou, jste připraveni na Bootstrap!** 🎉 |
|||
|
|||
--- |
|||
|
|||
## 📈 Co dál po Bootstrap? |
|||
|
|||
Po zvládnutí Bootstrap můžete pokračovat v: |
|||
- **Tailwind CSS** - utility-first framework |
|||
- **React** - JavaScript library pro UI |
|||
- **Vue.js** - progresivní JavaScript framework |
|||
- **SASS/SCSS** - CSS preprocessor |
|||
- **Node.js & Express** - backend JavaScript |
|||
- **Databáze** - MySQL, MongoDB |
|||
- **Full-stack projekty** |
|||
|
|||
--- |
|||
|
|||
## 🙏 Acknowledgments |
|||
|
|||
Projekty vytvořeny pro předmět **Webové Technologie** (WTL) |
|||
Cílová skupina: Studenti 3. ročníku IT |
|||
Generováno: 2025 |
|||
|
|||
--- |
|||
|
|||
**Hodně štěstí s projekty! Pokud máte jakékoliv dotazy, neváhejte se zeptat.** 🚀 |
|||
|
|||
--- |
|||
|
|||
## 📞 Kontakt na učitele |
|||
|
|||
Při problémech nebo dotazech se obraťte na vyučujícího během konzultačních hodin nebo přes školní email. |
|||
@ -0,0 +1,21 @@ |
|||
Ahoj, |
|||
|
|||
posílám seznam témát které budeme dělat na programovaní, na náš kurzu na amos "PRG 1 - ročník 25/26" (máme společně s Radkem Rybákem, máme je rozdělené na skupiny) |
|||
moje skupina má studijní materiály z hodiny zde: https://git.asgard.odbornaskola.cz/skrabanek/1i_prg |
|||
|
|||
Seznam témat: |
|||
- input, podminky, cykly |
|||
- ošetření chyb |
|||
- základní moduly (random, os, time, datetime) |
|||
- seznamy |
|||
- práce se soubory |
|||
- funkce |
|||
- pokročilá práce s funkcemi |
|||
- práce s textem a stringy |
|||
- instalace knihoven a pip |
|||
- CLI aplikace |
|||
- Objektově orientované programování (OOP) |
|||
- JSON & HTTP requests |
|||
|
|||
Děkuji, snad jsem na nic nezpoměl |
|||
Jakub Škrabánek |
|||
@ -0,0 +1,428 @@ |
|||
# Individuální studijní plán - Webové technologie (WTL) |
|||
## 3. ročník IT - školní rok 2025/2026 |
|||
|
|||
--- |
|||
|
|||
## Základní informace |
|||
|
|||
**Předmět:** Webové technologie (WTL) |
|||
**Ročník:** 3. ročník IT |
|||
**Vyučující:** [Jméno vyučujícího] |
|||
**Studijní materiály:** https://[odkaz na váš repozitář] |
|||
|
|||
--- |
|||
|
|||
## Celkový přehled kurzu |
|||
|
|||
Kurz Webových technologií je rozdělen do **dvou pololetí**: |
|||
|
|||
### **1. pololetí (září - leden)** |
|||
- Základy HTML, CSS a JavaScriptu |
|||
- Responzivní webdesign |
|||
- Bootstrap framework |
|||
- Webová bezpečnost (XSS útoky) |
|||
- Komplexní frontend projekty |
|||
|
|||
### **2. pololetí (únor - červen)** |
|||
- PHP základy |
|||
- Databáze (MySQL/MariaDB) |
|||
- Backend web development |
|||
- Webové aplikace (frontend + backend) |
|||
- Závěrečný projekt |
|||
|
|||
--- |
|||
|
|||
## 📋 Seznam témat - 1. pololetí (Frontend) |
|||
|
|||
### 1. Úvod do HTML |
|||
- Struktura HTML dokumentu |
|||
- Sémantické elementy (header, nav, main, footer, article, section, aside) |
|||
- Nadpisy, odstavce, seznamy |
|||
- Odkazy a obrázky |
|||
- Tabulky |
|||
- **Výstup:** Základní webová stránka |
|||
|
|||
### 2. HTML Formuláře |
|||
- Formulářové elementy (input, textarea, select, button) |
|||
- Typy inputů (text, email, password, number, date, atd.) |
|||
- Atributy formulářů (required, placeholder, pattern) |
|||
- **Výstup:** Kontaktní formulář |
|||
|
|||
### 3. Úvod do CSS |
|||
- Selektory (element, třída, ID) |
|||
- Box model (margin, padding, border) |
|||
- Barvy a pozadí |
|||
- Typografie (fonts, text styling) |
|||
- Pseudo-třídy (:hover, :visited, :focus) |
|||
- Gradienty |
|||
- **Výstup:** Nastylovaná webová stránka |
|||
|
|||
### 4. CSS Layout |
|||
- Display property (block, inline, inline-block) |
|||
- Float a clear (legacy layout) |
|||
- Základy pozicování (static, relative, absolute, fixed) |
|||
- **Výstup:** Vícesloupcový layout |
|||
|
|||
### 5. Úvod do JavaScriptu |
|||
- Proměnné (let, const, var) |
|||
- Datové typy (string, number, boolean, object, array) |
|||
- Operátory |
|||
- Podmínky (if, else, switch) |
|||
- Cykly (for, while) |
|||
- Funkce (function declaration, arrow functions) |
|||
- **Výstup:** Jednoduché JS skripty |
|||
|
|||
### 6. JavaScript + HTML |
|||
- DOM (Document Object Model) |
|||
- Manipulace s HTML elementy |
|||
- querySelector, getElementById |
|||
- innerHTML, innerText, textContent |
|||
- Vytváření a odstraňování elementů |
|||
- **Výstup:** Dynamická webová stránka |
|||
|
|||
### 7. JavaScript + CSS + DOM |
|||
- Manipulace s CSS přes JavaScript |
|||
- classList (add, remove, toggle) |
|||
- Změna stylů (style property) |
|||
- Event handling (onclick, addEventListener) |
|||
- **Výstup:** Interaktivní elementy (toggle, show/hide) |
|||
|
|||
### 8. JavaScript Formuláře |
|||
- Event handling u formulářů |
|||
- Validace formulářů s JavaScriptem |
|||
- preventDefault() |
|||
- Získávání hodnot z formulářů |
|||
- **Výstup:** Validovaný formulář |
|||
|
|||
### 9. Media Queries & Responzivní Design |
|||
- Viewport meta tag |
|||
- Media queries (@media) |
|||
- Breakpoints (mobile, tablet, desktop) |
|||
- Mobile-first přístup |
|||
- Responzivní obrázky |
|||
- **Výstup:** Responzivní webová stránka |
|||
|
|||
### 10. CSS Flexbox |
|||
- display: flex |
|||
- flex-direction, justify-content, align-items |
|||
- flex-wrap, gap |
|||
- Flex položky (flex-grow, flex-shrink, flex-basis) |
|||
- **Výstup:** Flexbox layout |
|||
|
|||
### 11. JSON & AJAX |
|||
- Formát JSON |
|||
- Fetch API |
|||
- Asynchronní JavaScript (promises, async/await) |
|||
- REST API základy |
|||
- **Výstup:** Aplikace načítající data z API |
|||
|
|||
### 12. CSS Grid |
|||
- display: grid |
|||
- grid-template-columns, grid-template-rows |
|||
- gap, grid-gap |
|||
- Grid areas |
|||
- Rozdíl Grid vs Flexbox |
|||
- **Výstup:** Grid-based layout |
|||
|
|||
--- |
|||
|
|||
## 🤖 AI Přípravné projekty (před Bootstrapem) |
|||
|
|||
### AI 01 - CSS Grid & Responzivní Layout |
|||
- Pokročilé Grid techniky |
|||
- nth-child selektory |
|||
- Komplexní responzivní design |
|||
- **Hodnocení:** 10 bodů |
|||
|
|||
### AI 02 - Sémantické HTML5 & CSS Positioning |
|||
- Sémantická struktura stránky |
|||
- Position: sticky, absolute, fixed, relative |
|||
- CSS jednotky (rem, em, vh, vw) |
|||
- **Hodnocení:** 15 bodů |
|||
|
|||
### AI 03 - Pokročilá Validace Formulářů |
|||
- addEventListener |
|||
- Regulární výrazy (RegEx) |
|||
- Real-time validace |
|||
- Visual feedback |
|||
- **Hodnocení:** 20 bodů |
|||
|
|||
### AI 04 - Komplexní Bootstrap Prep Projekt |
|||
- Kombinace všech předchozích konceptů |
|||
- CSS custom properties (variables) |
|||
- Pokročilé animace |
|||
- Modal, accordion implementace |
|||
- **Hodnocení:** 30 bodů |
|||
|
|||
**Celkem za AI projekty: 75 bodů** |
|||
|
|||
--- |
|||
|
|||
## 🎨 Bootstrap Framework |
|||
|
|||
### 13. Bootstrap Úvod |
|||
- Instalace a setup Bootstrapu |
|||
- Bootstrap grid systém |
|||
- Container, row, col |
|||
- Utility třídy |
|||
|
|||
### 14. Bootstrap Layout |
|||
- Responzivní breakpoints |
|||
- Grid options |
|||
- Flexbox utilities |
|||
- Spacing utilities (m-, p-) |
|||
|
|||
### 15. Bootstrap Komponenty |
|||
- Buttons, badges, alerts |
|||
- Cards |
|||
- Navbar |
|||
- Forms (Bootstrap form styling) |
|||
- Tables |
|||
|
|||
### 16. Bootstrap Carousel |
|||
- Carousel komponenta |
|||
- Indicators, controls |
|||
- Automatické přepínání |
|||
- **Výstup:** Fotogalerie s carousel |
|||
|
|||
### 17. Bootstrap Modal |
|||
- Modal dialog |
|||
- Triggery pro modal |
|||
- Modal velikosti |
|||
- **Výstup:** Aplikace s modal dialogy |
|||
|
|||
### 18. Bootstrap Form Validation |
|||
- Bootstrap validační třídy |
|||
- JavaScript validace s Bootstrapem |
|||
- Custom validation styles |
|||
- **Výstup:** Profesionální registrační formulář |
|||
|
|||
--- |
|||
|
|||
## 🔒 Webová bezpečnost |
|||
|
|||
### 19. XSS (Cross-Site Scripting) Demo |
|||
- Co je XSS útok |
|||
- Reflected XSS |
|||
- Stored XSS |
|||
- Prevence XSS útoků |
|||
- HTML sanitizace |
|||
- **Výstup:** Demo aplikace s XSS zranitelností a její oprava |
|||
|
|||
--- |
|||
|
|||
## 🚀 Komplexní Frontend projekty |
|||
|
|||
### 20. TODO List aplikace |
|||
- CRUD operace (Create, Read, Update, Delete) |
|||
- LocalStorage |
|||
- Bootstrap UI |
|||
- JavaScript manipulace s daty |
|||
- **Výstup:** Funkční TODO list |
|||
|
|||
### 21. AJAX & API Integration |
|||
- Fetch API pokročile |
|||
- Práce s REST API |
|||
- Error handling |
|||
- Loading states |
|||
- **Výstup:** Aplikace pracující s externím API |
|||
|
|||
--- |
|||
|
|||
## 📋 Seznam témat - 2. pololetí (Backend) |
|||
|
|||
### 22. Úvod do PHP |
|||
- PHP syntaxe |
|||
- Proměnné a datové typy |
|||
- Podmínky a cykly |
|||
- Funkce v PHP |
|||
- Superglobals ($_GET, $_POST, $_SERVER) |
|||
|
|||
### 23. PHP & Formuláře |
|||
- Zpracování formulářů (GET, POST) |
|||
- Validace na straně serveru |
|||
- Sanitizace vstupů |
|||
- CSRF ochrana |
|||
|
|||
### 24. PHP & Soubory |
|||
- Čtení a zápis souborů |
|||
- Nahrávání souborů |
|||
- Práce s adresáři |
|||
- File permissions |
|||
|
|||
### 25. Úvod do databází |
|||
- Relační databáze |
|||
- MySQL/MariaDB |
|||
- phpMyAdmin |
|||
- SQL příkazy (SELECT, INSERT, UPDATE, DELETE) |
|||
|
|||
### 26. PHP & MySQL |
|||
- Připojení k databázi (mysqli, PDO) |
|||
- Prepared statements |
|||
- SQL injection prevence |
|||
- Databázové dotazy z PHP |
|||
|
|||
### 27. Sessions & Cookies |
|||
- HTTP sessions |
|||
- Cookies |
|||
- Autentizace uživatelů |
|||
- Session security |
|||
|
|||
### 28. Registrace & Login systém |
|||
- Uživatelská registrace |
|||
- Hash hesel (password_hash, password_verify) |
|||
- Login/logout funkcionalita |
|||
- Ochrana stránek (middleware) |
|||
|
|||
### 29. CRUD Webová aplikace |
|||
- Create, Read, Update, Delete operace |
|||
- Databázové operace |
|||
- Admin rozhraní |
|||
- **Výstup:** Blog nebo e-shop backend |
|||
|
|||
### 30. REST API v PHP |
|||
- JSON responses |
|||
- API endpoints |
|||
- HTTP metody (GET, POST, PUT, DELETE) |
|||
- API authentication |
|||
|
|||
### 31. Závěrečný projekt |
|||
- Komplexní webová aplikace |
|||
- Frontend (HTML, CSS, JS, Bootstrap) |
|||
- Backend (PHP, MySQL) |
|||
- Funkční features (registrace, login, CRUD) |
|||
- Responzivní design |
|||
- **Hodnocení:** 100 bodů |
|||
|
|||
--- |
|||
|
|||
## 🎯 Očekávané výstupy kurzu |
|||
|
|||
Po dokončení kurzu by studenti měli umět: |
|||
|
|||
### Frontend: |
|||
✅ Vytvořit sémanticky správnou HTML strukturu |
|||
✅ Nastylovat moderní responzivní web pomocí CSS |
|||
✅ Používat CSS Grid a Flexbox pro layout |
|||
✅ Psát čistý a efektivní JavaScript kód |
|||
✅ Manipulovat s DOM a zpracovávat eventy |
|||
✅ Validovat formuláře |
|||
✅ Pracovat s JSON a API pomocí Fetch |
|||
✅ Používat Bootstrap framework |
|||
✅ Rozumět základům webové bezpečnosti (XSS) |
|||
|
|||
### Backend: |
|||
✅ Psát PHP skripty |
|||
✅ Zpracovávat formuláře na serveru |
|||
✅ Pracovat s MySQL databází |
|||
✅ Vytvořit registrační a přihlašovací systém |
|||
✅ Implementovat CRUD operace |
|||
✅ Zabezpečit webovou aplikaci (SQL injection, XSS, CSRF) |
|||
✅ Vytvořit jednoduché REST API |
|||
|
|||
### Soft skills: |
|||
✅ Debugovat kód pomocí Developer Tools |
|||
✅ Používat Git pro verzování kódu |
|||
✅ Psát čitelný a udržovatelný kód |
|||
✅ Testovat aplikace v různých prohlížečích |
|||
✅ Pracovat samostatně i v týmu |
|||
|
|||
--- |
|||
|
|||
## 📊 Hodnocení |
|||
|
|||
### 1. pololetí: |
|||
- **AI projekty:** 75 bodů (AI 01-04) |
|||
- **Průběžné projekty:** 50 bodů |
|||
- **Aktivita a domácí úkoly:** 25 bodů |
|||
- **Test z frontend technologií:** 50 bodů |
|||
- **Celkem:** 200 bodů |
|||
|
|||
### 2. pololetí: |
|||
- **PHP & MySQL projekty:** 50 bodů |
|||
- **Závěrečný projekt:** 100 bodů |
|||
- **Aktivita a domácí úkoly:** 25 bodů |
|||
- **Test z backend technologií:** 25 bodů |
|||
- **Celkem:** 200 bodů |
|||
|
|||
### Celkové hodnocení za rok: 400 bodů |
|||
|
|||
**Klasifikace:** |
|||
- 90-100% (360-400 bodů): Výborný (1) |
|||
- 75-89% (300-359 bodů): Chvalitebný (2) |
|||
- 60-74% (240-299 bodů): Dobrý (3) |
|||
- 45-59% (180-239 bodů): Dostatečný (4) |
|||
- 0-44% (0-179 bodů): Nedostatečný (5) |
|||
|
|||
--- |
|||
|
|||
## 🛠️ Doporučené nástroje |
|||
|
|||
### Editor: |
|||
- **Visual Studio Code** (primární doporučení) |
|||
- Extensions: Live Server, Prettier, Auto Rename Tag, CSS Peek |
|||
|
|||
### Prohlížeče: |
|||
- **Google Chrome** (primární pro vývoj) |
|||
- Firefox, Edge (testování kompatibility) |
|||
- Chrome DevTools (F12) pro debugging |
|||
|
|||
### Backend (2. pololetí): |
|||
- **XAMPP** nebo **WAMP** (Apache + MySQL + PHP) |
|||
- **phpMyAdmin** (správa databáze) |
|||
|
|||
### Ostatní: |
|||
- **Git** pro verzování kódu |
|||
- **GitHub/GitLab** pro sdílení projektů |
|||
|
|||
--- |
|||
|
|||
## 📚 Užitečné zdroje |
|||
|
|||
### Dokumentace: |
|||
- [MDN Web Docs](https://developer.mozilla.org/) - HTML, CSS, JavaScript |
|||
- [Bootstrap dokumentace](https://getbootstrap.com/docs/) |
|||
- [PHP dokumentace](https://www.php.net/manual/en/) |
|||
- [MySQL dokumentace](https://dev.mysql.com/doc/) |
|||
|
|||
### Online nástroje: |
|||
- [CodePen](https://codepen.io/) - Online playground |
|||
- [regex101.com](https://regex101.com/) - RegEx tester |
|||
- [Can I Use](https://caniuse.com/) - Browser compatibility |
|||
- [CSS-Tricks](https://css-tricks.com/) - CSS tutoriály |
|||
|
|||
### Komunita: |
|||
- [Stack Overflow](https://stackoverflow.com/) - Q&A |
|||
- [CSS Tricks](https://css-tricks.com/) |
|||
- [JavaScript.info](https://javascript.info/) |
|||
|
|||
--- |
|||
|
|||
## 📞 Kontakt |
|||
|
|||
**Vyučující:** [Jméno vyučujícího] |
|||
**Email:** [email] |
|||
**Konzultační hodiny:** [časy] |
|||
**Repozitář:** [odkaz na Git repozitář] |
|||
|
|||
--- |
|||
|
|||
## 📝 Poznámky |
|||
|
|||
- Všechny projekty a úkoly budou zadávány průběžně během školního roku |
|||
- Studenti jsou povinni dodržovat termíny odevzdání |
|||
- Plagiátorství (kopírování kódu) bude sankcionováno |
|||
- Aktivní účast na hodinách je důležitá pro pochopení látky |
|||
- Doporučuje se pravidelné opakování a procvičování |
|||
- Studenti mohou využít konzultační hodiny pro pomoc s projekty |
|||
|
|||
--- |
|||
|
|||
**Vytvořeno:** [datum] |
|||
**Předmět:** Webové Technologie (WTL) |
|||
**Cílová skupina:** 3. ročník IT |
|||
**Školní rok:** 2025/2026 |
|||
|
|||
--- |
|||
|
|||
*Tento studijní plán může být upraven na základě potřeb studentů a aktuálního pokroku ve výuce.* |
|||
@ -0,0 +1,31 @@ |
|||
Ahoj, |
|||
|
|||
posílám seznam témat které budeme dělat na Webových technologiích, na náš kurzu "WTL - 3. ročník 25/26" |
|||
studijní materiály z hodiny zde: [odkaz na repozitář] |
|||
|
|||
Seznam témat - 1. pololetí (Frontend): |
|||
- úvod do HTML (struktura, sémantika, formuláře, tabulky) |
|||
- úvod do CSS (selektory, box model, barvy, typografie) |
|||
- CSS layout (float, positioning, flexbox, grid) |
|||
- media queries a responzivní design |
|||
- úvod do JavaScriptu (proměnné, podmínky, cykly, funkce) |
|||
- JavaScript + DOM (manipulace s HTML, querySelector, innerHTML) |
|||
- JavaScript eventy a validace formulářů |
|||
- JSON & Fetch API (asynchronní JavaScript, REST API) |
|||
- Bootstrap framework (grid systém, komponenty, utilities) |
|||
- Bootstrap pokročile (carousel, modal, form validation) |
|||
- webová bezpečnost (XSS útoky, prevence, sanitizace) |
|||
- komplexní frontend projekty (TODO list, AJAX aplikace) |
|||
|
|||
Seznam témat - 2. pololetí (Backend): |
|||
- úvod do PHP (syntaxe, proměnné, podmínky, cykly, funkce) |
|||
- PHP formuláře (GET, POST, validace, sanitizace) |
|||
- PHP práce se soubory (čtení, zápis, upload) |
|||
- úvod do databází (MySQL, SQL příkazy) |
|||
- PHP & MySQL (připojení, dotazy, prepared statements) |
|||
- sessions & cookies (autentizace, zabezpečení) |
|||
- registrace & login systém (hash hesel, ochrana) |
|||
- závěrečný full-stack projekt (frontend + backend + databáze) |
|||
|
|||
Děkuji, snad jsem na nic nezapomněl |
|||
[Tvoje jméno] |
|||
@ -0,0 +1,101 @@ |
|||
# 📚 AI Extra Material - Doplňkové Studijní Materiály |
|||
|
|||
## 🎯 Účel této složky |
|||
|
|||
Tato složka obsahuje **doplňkové studijní materiály** pro hlubší pochopení pokročilých konceptů webového vývoje. Tyto materiály jsou navíc k základnímu učivu a slouží k samostudiu. |
|||
|
|||
## 📂 Co složka obsahuje |
|||
|
|||
### 🎓 AI Projekty (Základní verze v /AI složce) |
|||
|
|||
Tato složka obsahuje **duplikáty AI projektů** z hlavní složky `/AI`. Jsou zde pro pohodlný přístup k materiálům. |
|||
|
|||
- **ai_01_grid_responsive** - CSS Grid & Responzivní Layout |
|||
- **ai_02_semantic_portfolio** - Sémantické HTML5 & CSS Positioning |
|||
- **ai_03_form_validation** - Pokročilá Validace Formulářů s JavaScript |
|||
- **ai_04_prep_bootstrap** - Komplexní Bootstrap Prep Projekt |
|||
|
|||
### 📋 Informační Soubory |
|||
|
|||
- **AI_PROJEKTY_README.md** - Přehled všech AI projektů |
|||
- **UCITEL_INFO.md** - Informace pro učitele o projektech, hodnocení, harmonogramu |
|||
- **ISP_WTL_3I.md** - Individuální studijní plán (ISP) |
|||
- **ISP_WTL_3I.txt** - ISP v textové podobě |
|||
|
|||
### 🚀 Bootstrap Doplňkové Projekty |
|||
|
|||
#### 18_form_validation_bootstrap |
|||
Ukázka validace formulářů s Bootstrap 5. |
|||
- Bootstrap validační třídy |
|||
- Custom validace s JavaScriptem |
|||
- Visual feedback pro uživatele |
|||
- Propojení s Bootstrap styly |
|||
|
|||
**Kdy použít:** Pro pochopení, jak Bootstrap řeší validaci formulářů "out of the box". |
|||
|
|||
#### 18a_form_xss_demo |
|||
**BEZPEČNOSTNÍ DEMO** - ukázka XSS (Cross-Site Scripting) zranitelnosti. |
|||
- Demonstrace nebezpečného kódu |
|||
- Jak vznikají XSS útoky |
|||
- Jak se bránit (sanitizace inputů) |
|||
- Best practices pro bezpečnost |
|||
|
|||
**⚠️ VAROVÁNÍ:** Tento kód je záměrně zranitelný pro výukové účely. **NIKDY** nepoužívejte tento přístup v produkčním kódu! |
|||
|
|||
## 🎓 Jak pracovat s těmito materiály |
|||
|
|||
### Pro studenty: |
|||
|
|||
1. **Nejdříve dokončete základní AI projekty** v hlavní složce `/AI` |
|||
2. **Pokud chcete víc:** Projděte si tyto doplňkové materiály |
|||
3. **Bootstrap validace:** Po dokončení AI 03, prozkoumejte `18_form_validation_bootstrap` |
|||
4. **Bezpečnost:** Po práci s formuláři si prostudujte `18a_form_xss_demo` |
|||
|
|||
### Pro učitele: |
|||
|
|||
- Přečtěte si **UCITEL_INFO.md** pro detailní informace o projektech |
|||
- **AI_PROJEKTY_README.md** obsahuje přehled všech AI projektů |
|||
- **ISP** soubory obsahují studijní plán |
|||
|
|||
## 🔗 Návaznost na hlavní kurz |
|||
|
|||
| Základní kurz | Extra Material | Proč je užitečný | |
|||
|---------------|----------------|------------------| |
|||
| 08_js_form | 18_form_validation_bootstrap | Ukáže Bootstrap přístup k validaci | |
|||
| AI 03 | 18a_form_xss_demo | Bezpečnostní aspekty formulářů | |
|||
| 13-17 Bootstrap | AI projekty (duplikáty) | Opakování před Bootstrapem | |
|||
|
|||
## 💡 Doporučené Pořadí Studia |
|||
|
|||
1. **Základní kurz** (01-20) - absolvujte nejdříve |
|||
2. **AI projekty** v hlavní složce `/AI` - praktické projekty |
|||
3. **Bootstrap validace** (`18_form_validation_bootstrap`) - po Bootstrap lekcích |
|||
4. **XSS Demo** (`18a_form_xss_demo`) - pro pochopení bezpečnosti |
|||
5. **ISP materiály** - pro samostudium dle potřeby |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
- ✅ Tyto materiály jsou **nepovinné** - jsou navíc k základnímu kurzu |
|||
- ✅ Projekty v této složce jsou **duplikáty** - hlavní verze jsou v `/AI` |
|||
- ⚠️ **XSS Demo** je záměrně zranitelný - slouží pouze k výukovým účelům |
|||
- 📚 **UCITEL_INFO.md** obsahuje hodnocení a harmonogram pro učitele |
|||
|
|||
## 📖 Hlavní AI Projekty |
|||
|
|||
**POZOR:** Hlavní verze AI projektů jsou v kořenové složce **`/AI`**! |
|||
|
|||
Pro práci na projektech používejte soubory z `/AI`, ne z této složky. Tato složka slouží jako archiv a reference. |
|||
|
|||
## 🎯 Cíle Extra Materiálů |
|||
|
|||
Po prostudování těchto materiálů budete: |
|||
- ✅ Rozumět Bootstrap validaci formulářů |
|||
- ✅ Vědět, jak se bránit XSS útokům |
|||
- ✅ Mít hlubší pochopení bezpečnosti webových aplikací |
|||
- ✅ Umět propojit Bootstrap s custom validací |
|||
|
|||
--- |
|||
|
|||
**Hodně štěstí s dalším studiem! 📚✨** |
|||
|
|||
*Tyto materiály rozšiřují základní kurz a poskytují hlubší vhled do pokročilých témat.* |
|||
@ -0,0 +1,351 @@ |
|||
# 👨🏫 Informace pro učitele - AI Projekty |
|||
|
|||
## 📊 Analýza současného stavu studentů |
|||
|
|||
### ✅ Co studenti již zvládají: |
|||
|
|||
**HTML:** |
|||
- Základní struktura, nadpisy (h1-h6) |
|||
- Odkazy, obrázky |
|||
- Formuláře (input, textarea, select, button) |
|||
- Tabulky a seznamy |
|||
- Částečně sémantické elementy (header, footer, aside, article) |
|||
|
|||
**CSS:** |
|||
- Základní selektory (element, třída, ID) |
|||
- Box model (margin, padding, border) |
|||
- Pseudo-třídy (:hover, :visited) |
|||
- Gradienty a transitions |
|||
- Flexbox (základy) |
|||
- Media queries (základy) |
|||
- Float-based layout (starší přístup) |
|||
|
|||
**JavaScript:** |
|||
- Proměnné (let, const, var) |
|||
- Datové typy a objekty |
|||
- Podmínky a cykly |
|||
- Funkce |
|||
- DOM manipulace (getElementById, innerHTML, innerText) |
|||
- Event handling (inline onclick) |
|||
- JSON a Fetch API |
|||
|
|||
### ⚠️ Co chybí před Bootstrapem: |
|||
|
|||
**KRITICKÉ mezery:** |
|||
1. **CSS Grid** - chybí úplně |
|||
2. **addEventListener** - používají jen inline onclick |
|||
3. **Pokročilé CSS selektory** (nth-child, ::before, ::after) |
|||
4. **CSS jednotky** - používají jen px, ne rem/em/vh/vw |
|||
5. **Position: sticky a absolute** - nepoužito |
|||
6. **Form validace s JS** - jen základní |
|||
|
|||
**DOPORUČUJI doplnit:** |
|||
7. **CSS proměnné** (custom properties) |
|||
8. **Pokročilé animace** |
|||
9. **Scroll efekty** |
|||
10. **Mobile-first přístup** |
|||
|
|||
--- |
|||
|
|||
## 🎯 Účel AI projektů |
|||
|
|||
Projekty byly navrženy tak, aby: |
|||
1. **Systematicky doplnily mezery** v znalostech |
|||
2. **Postupně zvyšovaly náročnost** (od jednoduchého po komplexní) |
|||
3. **Připravily na Bootstrap filozofii** (grid systém, utility třídy, komponenty) |
|||
4. **Poskytly praktickou zkušenost** s real-world projekty |
|||
|
|||
--- |
|||
|
|||
## 📋 Přehled projektů pro učitele |
|||
|
|||
### AI 01 - CSS Grid & Responzivní Layout |
|||
**Čas:** 1-2 vyučovací hodiny |
|||
**Obtížnost:** Střední |
|||
**Cíl:** Naučit CSS Grid před Bootstrap grid systémem |
|||
|
|||
**Klíčové koncepty:** |
|||
- `display: grid` |
|||
- `grid-template-columns` |
|||
- `gap` |
|||
- Pokročilé selektory (nth-child) |
|||
- Media queries pro responzivitu |
|||
|
|||
**Výstup:** Responzivní galerie s 9 položkami |
|||
|
|||
--- |
|||
|
|||
### AI 02 - Sémantické HTML5 & CSS Positioning |
|||
**Čas:** 2-3 vyučovací hodiny |
|||
**Obtížnost:** Náročné |
|||
**Cíl:** Sémantický HTML5 a všechny typy positioning |
|||
|
|||
**Klíčové koncepty:** |
|||
- Sémantické elementy (nav, main, section, article, aside) |
|||
- Position: fixed, sticky, relative, absolute |
|||
- CSS jednotky: rem, em, vh, vw |
|||
- Správná struktura moderní stránky |
|||
|
|||
**Výstup:** Portfolio stránka s fixní navigací a sticky sidebar |
|||
|
|||
--- |
|||
|
|||
### AI 03 - Pokročilá Validace Formulářů |
|||
**Čas:** 2-3 vyučovací hodiny |
|||
**Obtížnost:** Náročné |
|||
**Cíl:** Real-time validace s JS (Bootstrap má validační třídy) |
|||
|
|||
**Klíčové koncepty:** |
|||
- `addEventListener` místo inline events |
|||
- RegEx pro validaci |
|||
- DOM manipulace (classList) |
|||
- Real-time feedback |
|||
- UX best practices |
|||
|
|||
**Výstup:** Registrační formulář s kompletní validací |
|||
|
|||
--- |
|||
|
|||
### AI 04 - Komplexní Bootstrap Prep Projekt |
|||
**Čas:** 4-6 vyučovacích hodin (nebo domácí práce) |
|||
**Obtížnost:** Velmi náročné |
|||
**Cíl:** Komplexní projekt kombinující všechny koncepty |
|||
|
|||
**Klíčové koncepty:** |
|||
- Všechny předchozí koncepty |
|||
- CSS proměnné |
|||
- Scroll efekty |
|||
- Modal, accordion |
|||
- Mobile-first |
|||
|
|||
**Výstup:** Plně funkční landing page |
|||
|
|||
--- |
|||
|
|||
## 📅 Doporučený harmonogram |
|||
|
|||
### Varianta A - Intenzivní (2 týdny) |
|||
``` |
|||
Týden 1: |
|||
Po: AI 01 + AI 02 začátek |
|||
St: AI 02 dokončení + AI 03 začátek |
|||
Pá: AI 03 dokončení |
|||
|
|||
Týden 2: |
|||
Po-Pá: AI 04 (průběžně) |
|||
Pá: Prezentace AI 04 |
|||
|
|||
Týden 3: |
|||
Bootstrap start! |
|||
``` |
|||
|
|||
### Varianta B - Standardní (3 týdny) |
|||
``` |
|||
Týden 1: |
|||
Lekce 1: AI 01 |
|||
Lekce 2: AI 02 |
|||
|
|||
Týden 2: |
|||
Lekce 1: AI 03 část 1 |
|||
Lekce 2: AI 03 část 2 |
|||
|
|||
Týden 3: |
|||
Lekce 1-2: AI 04 (práce ve třídě) |
|||
DÚ: Dokončení AI 04 |
|||
|
|||
Týden 4: |
|||
Bootstrap start! |
|||
``` |
|||
|
|||
### Varianta C - Volnočasová (4 týdny) |
|||
``` |
|||
Týden 1: AI 01 |
|||
Týden 2: AI 02 |
|||
Týden 3: AI 03 |
|||
Týden 4: AI 04 |
|||
|
|||
Týden 5: Bootstrap start! |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## 🎓 Hodnocení projektů |
|||
|
|||
### AI 01 (10 bodů) |
|||
- HTML struktura (2b) |
|||
- CSS Grid implementace (3b) |
|||
- Media queries (2b) |
|||
- Pokročilé selektory (2b) |
|||
- Responzivita (1b) |
|||
|
|||
### AI 02 (15 bodů) |
|||
- Sémantická struktura (4b) |
|||
- Position: fixed, sticky (3b) |
|||
- Position: relative, absolute (3b) |
|||
- CSS jednotky (rem, em, vh) (2b) |
|||
- Responzivita (3b) |
|||
|
|||
### AI 03 (20 bodů) |
|||
- addEventListener použití (4b) |
|||
- Validační funkce (6b) |
|||
- RegEx implementace (3b) |
|||
- Visual feedback (4b) |
|||
- Submit handling (3b) |
|||
|
|||
### AI 04 (30 bodů) |
|||
- HTML struktura (5b) |
|||
- CSS Grid & Flexbox (6b) |
|||
- Positioning (4b) |
|||
- JavaScript interaktivita (6b) |
|||
- Responzivita (4b) |
|||
- Design & UX (3b) |
|||
- Clean code (2b) |
|||
|
|||
**Celkem: 75 bodů** |
|||
|
|||
--- |
|||
|
|||
## 💡 Tips pro učitele |
|||
|
|||
### Při výuce AI 01: |
|||
1. Začněte s vysvětlením rozdílu Grid vs Flexbox |
|||
2. Ukažte Chrome DevTools - Grid overlay |
|||
3. Procvičte nth-child na příkladech |
|||
4. Zdůrazněte mobile-first přístup |
|||
|
|||
### Při výuce AI 02: |
|||
1. Narýsujte positioning na tabuli (fixed, sticky, relative, absolute) |
|||
2. Ukažte proč používat rem místo px |
|||
3. Vysvětlete z-index context |
|||
4. Zdůrazněte důležitost sémantiky pro SEO |
|||
|
|||
### Při výuce AI 03: |
|||
1. Živě ukažte addEventListener vs onclick |
|||
2. Procvičte RegEx na regex101.com |
|||
3. Vysvětlete event.preventDefault() |
|||
4. Ukažte console.log() debugging |
|||
|
|||
### Při výuce AI 04: |
|||
1. Nechte studenty pracovat samostatně |
|||
2. Buďte dostupní pro konzultace |
|||
3. Povzbuďte kreativitu |
|||
4. Na konci nechte studenty prezentovat |
|||
|
|||
--- |
|||
|
|||
## 🔧 Troubleshooting - Časté problémy studentů |
|||
|
|||
### CSS Grid: |
|||
**Problem:** "Grid nefunguje" |
|||
**Řešení:** Zkontrolujte `display: grid` na kontejneru, ne na položkách |
|||
|
|||
### Positioning: |
|||
**Problem:** "Absolute element je mimo stránku" |
|||
**Řešení:** Parent musí mít `position: relative` |
|||
|
|||
### addEventListener: |
|||
**Problem:** "Funkce se volá hned při načtení" |
|||
**Řešení:** Nepsat `validateName()` ale jen `validateName` (bez závorek) |
|||
|
|||
### RegEx: |
|||
**Problem:** "RegEx nefunguje" |
|||
**Řešení:** Otestujte na regex101.com, možná chybí escape znaky |
|||
|
|||
### Media queries: |
|||
**Problem:** "Responzivita nefunguje" |
|||
**Řešení:** Zkontrolujte `<meta name="viewport">` v head |
|||
|
|||
--- |
|||
|
|||
## 📊 Očekávané výsledky |
|||
|
|||
Po dokončení všech projektů by studenti měli: |
|||
|
|||
### Znát: |
|||
✅ Rozdíl mezi Grid a Flexbox a kdy co použít |
|||
✅ Všechny typy CSS positioning |
|||
✅ Jak vytvořit responzivní layout bez frameworku |
|||
✅ Jak validovat formuláře v JavaScriptu |
|||
✅ addEventListener a event handling |
|||
✅ Základy RegEx |
|||
✅ Mobile-first přístup |
|||
|
|||
### Umět: |
|||
✅ Vytvořit komplexní responzivní stránku |
|||
✅ Implementovat interaktivní funkce |
|||
✅ Validovat formuláře s visual feedbackem |
|||
✅ Používat pokročilé CSS selektory |
|||
✅ Debugovat pomocí Developer Tools |
|||
|
|||
### Být připraveni na: |
|||
✅ Bootstrap grid systém (pochopí jak funguje) |
|||
✅ Bootstrap komponenty (pochopí co řeší) |
|||
✅ Bootstrap utilities (pochopí proč existují) |
|||
✅ Přizpůsobení frameworku vlastním potřebám |
|||
|
|||
--- |
|||
|
|||
## 🎯 Přechod na Bootstrap |
|||
|
|||
Po dokončení AI projektů vysvětlete studentům: |
|||
|
|||
1. **Co Bootstrap řeší:** |
|||
- "Vzpomínáte, jak jste v AI 01 vytvářeli grid systém? Bootstrap to má už hotové." |
|||
- "Vzpomínáte na validaci formuláře v AI 03? Bootstrap má validační třídy." |
|||
|
|||
2. **Proč jsme to dělali ručně:** |
|||
- "Teď rozumíte, co Bootstrap dělá pod kapotou." |
|||
- "Když něco nebude fungovat, budete vědět proč." |
|||
- "Umíte to bez frameworku = jste lepší developer." |
|||
|
|||
3. **Kdy použít Bootstrap vs custom CSS:** |
|||
- Bootstrap: Rychlé prototypování, standardní projekty |
|||
- Custom: Unikátní design, optimalizace, portfolio projekty |
|||
|
|||
--- |
|||
|
|||
## 📞 Podpora |
|||
|
|||
Pokud najdete chyby v projektech nebo máte návrhy na zlepšení, kontaktujte: |
|||
- GitHub Issues v repozitáři |
|||
- Email učiteli |
|||
- Během konzultačních hodin |
|||
|
|||
--- |
|||
|
|||
## 📝 Poznámky k implementaci |
|||
|
|||
### Struktura souborů: |
|||
``` |
|||
ai_XX_project_name/ |
|||
├── ZADANI.md # Detailní zadání pro studenty |
|||
├── index.html # Startovací HTML (s TODO komentáři) |
|||
├── style.css # CSS šablona (s TODO komentáři) |
|||
├── script.js # JS šablona (s TODO komentáři) |
|||
├── reseni.html # Kompletní řešení |
|||
├── reseni.css # CSS s podrobnými komentáři |
|||
└── reseni.js # JS s podrobnými komentáři |
|||
``` |
|||
|
|||
### Filozofie: |
|||
- **Startovací soubory** obsahují TODO a strukturu |
|||
- **Řešení** obsahuje detailní komentáře vysvětlující každý řádek |
|||
- **ZADANI.md** obsahuje learning objectives a užitečné odkazy |
|||
|
|||
--- |
|||
|
|||
## 🎉 Závěr |
|||
|
|||
Tyto projekty důkladně připraví studenty na Bootstrap. Investovaný čas se vrátí v: |
|||
- Lepším pochopení frameworku |
|||
- Schopnosti přizpůsobení |
|||
- Debugovacích dovednostech |
|||
- Celkově lepších web development skills |
|||
|
|||
**Hodně štěstí při výuce!** 🚀 |
|||
|
|||
--- |
|||
|
|||
Vytvořeno: 24. října 2025 |
|||
Předmět: Webové Technologie (WTL) |
|||
Cílová skupina: 3. ročník IT |
|||
@ -0,0 +1,158 @@ |
|||
# AI 01 - CSS Grid & Responzivní Layout |
|||
|
|||
## 🎯 Cíl projektu |
|||
|
|||
Naučit se pracovat s **CSS Grid systémem** a **pokročilými CSS selektory**, které jsou důležité pro pochopení Bootstrap grid systému. |
|||
|
|||
## 📋 Co se naučíte |
|||
|
|||
- **CSS Grid základy** - `display: grid`, `grid-template-columns` |
|||
- **Grid gaps** - mezery mezi položkami |
|||
- **Responzivní grid** s media queries |
|||
- **Pokročilé CSS selektory** - `:nth-child()`, `:first-child`, `:last-child` |
|||
- **CSS transformace** - `scale()` při hover |
|||
- **Grid template areas** - pojmenované oblasti |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- **ZADANI.md** - detailní zadání projektu s požadavky |
|||
- **index.html** - startovací HTML soubor (s TODO komentáři pro vás) |
|||
- **style.css** - CSS šablona (s TODO komentáři) |
|||
- **reseni.html** - kompletní řešení (podívejte se, když zaseknete) |
|||
- **reseni.css** - CSS s podrobnými komentáři vysvětlující každý řádek |
|||
|
|||
## 🚀 Jak pracovat s projektem |
|||
|
|||
### Krok 1: Přečtěte si ZADANI.md |
|||
- Otevřete `ZADANI.md` a přečtěte si celé zadání |
|||
- Pochopte, co máte vytvořit |
|||
- Prohlédněte si ukázky kódu |
|||
|
|||
### Krok 2: Začněte s index.html a style.css |
|||
- Otevřete `index.html` a `style.css` |
|||
- Najděte **TODO komentáře** - to jsou místa, kde máte psát kód |
|||
- Postupujte podle TODO instrukcí |
|||
|
|||
### Krok 3: Testujte responzivitu |
|||
1. Otevřete `index.html` v prohlížeči |
|||
2. Otevřete Developer Tools (F12) |
|||
3. Zapněte Device Toolbar (Ctrl+Shift+M) |
|||
4. Testujte různé velikosti: |
|||
- Desktop (> 768px) - 3 sloupce |
|||
- Tablet (768px) - 2 sloupce |
|||
- Mobil (480px) - 1 sloupec |
|||
|
|||
### Krok 4: Když se zaseknete |
|||
- Podívejte se do `reseni.css` - jsou tam podrobné komentáře |
|||
- Zkuste pochopit PROČ to funguje, ne jen zkopírovat |
|||
- Porovnejte své řešení s hotovým |
|||
|
|||
## 💡 Klíčové koncepty |
|||
|
|||
### CSS Grid pattern: |
|||
```css |
|||
/* Kontejner */ |
|||
.grid-container { |
|||
display: grid; /* MUSÍ BÝT! */ |
|||
grid-template-columns: repeat(3, 1fr); /* 3 sloupce */ |
|||
gap: 20px; /* mezery */ |
|||
} |
|||
|
|||
/* Položky se umístí automaticky */ |
|||
.grid-item { |
|||
background-color: lightblue; |
|||
padding: 20px; |
|||
} |
|||
``` |
|||
|
|||
### Responzivní breakpointy: |
|||
```css |
|||
/* Desktop (výchozí) - 3 sloupce */ |
|||
.grid-container { |
|||
grid-template-columns: repeat(3, 1fr); |
|||
} |
|||
|
|||
/* Tablet */ |
|||
@media (max-width: 768px) { |
|||
.grid-container { |
|||
grid-template-columns: repeat(2, 1fr); |
|||
} |
|||
} |
|||
|
|||
/* Mobil */ |
|||
@media (max-width: 480px) { |
|||
.grid-container { |
|||
grid-template-columns: 1fr; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Pokročilé selektory: |
|||
```css |
|||
/* Liché položky (1, 3, 5, ...) */ |
|||
.grid-item:nth-child(odd) { |
|||
background-color: lightblue; |
|||
} |
|||
|
|||
/* Sudé položky (2, 4, 6, ...) */ |
|||
.grid-item:nth-child(even) { |
|||
background-color: lightgreen; |
|||
} |
|||
|
|||
/* První položka */ |
|||
.grid-item:first-child { |
|||
background-color: gold; |
|||
} |
|||
|
|||
/* Poslední položka */ |
|||
.grid-item:last-child { |
|||
background-color: pink; |
|||
} |
|||
|
|||
/* Hover efekt */ |
|||
.grid-item:hover { |
|||
transform: scale(1.05); /* zvětší o 5% */ |
|||
cursor: pointer; |
|||
} |
|||
``` |
|||
|
|||
## ⚠️ Časté chyby |
|||
|
|||
❌ **Grid nefunguje** |
|||
→ Zapomněli jste `display: grid` na kontejneru |
|||
|
|||
❌ **Responzivita nefunguje** |
|||
→ Chybí `<meta name="viewport">` v `<head>` |
|||
|
|||
❌ **nth-child nefunguje** |
|||
→ Zkontrolujte syntax: `:nth-child(odd)` ne `.nth-child(odd)` |
|||
|
|||
❌ **Gap nefunguje** |
|||
→ `gap` funguje pouze v grid/flex containeru |
|||
|
|||
## 🎓 Hodnocení (10 bodů) |
|||
|
|||
- **HTML struktura** (2b) - správná struktura, 9+ položek |
|||
- **CSS Grid implementace** (3b) - grid-template-columns, gap |
|||
- **Media queries** (2b) - 3 breakpointy (desktop, tablet, mobil) |
|||
- **Pokročilé selektory** (2b) - nth-child, first/last-child, hover |
|||
- **Responzivita** (1b) - funguje na všech zařízeních |
|||
|
|||
## 🔗 Užitečné odkazy |
|||
|
|||
- [CSS Grid Guide - CSS Tricks](https://css-tricks.com/snippets/css/complete-guide-grid/) |
|||
- [nth-child selector - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child) |
|||
- [CSS Transform - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) |
|||
|
|||
## ⏱️ Odhadovaný čas |
|||
|
|||
**45-60 minut** |
|||
|
|||
## 🎯 Po dokončení |
|||
|
|||
Po dokončení tohoto projektu budete rozumět: |
|||
- Jak funguje CSS Grid (základ pro Bootstrap grid) |
|||
- Jak vytvořit responzivní layout bez frameworku |
|||
- Pokročilé CSS selektory |
|||
|
|||
➡️ **Další projekt:** AI 02 - Sémantické HTML5 & CSS Positioning |
|||
@ -0,0 +1,49 @@ |
|||
# AI 01 - CSS Grid & Responzivní Layout |
|||
|
|||
## 🎯 Cíl projektu |
|||
Naučit se pracovat s CSS Grid systémem a pokročilými CSS selektory, které jsou důležité pro pochopení Bootstrap grid systému. |
|||
|
|||
## 📝 Zadání |
|||
|
|||
Vytvořte responzivní галерию obrázků s následujícími vlastnostmi: |
|||
|
|||
### HTML požadavky: |
|||
1. Vytvořte stránku s hlavičkou (h1) "Galerie Obrázků" |
|||
2. Vytvořte grid kontejner s minimálně 9 položkami (divy s třídou "grid-item") |
|||
3. Každá položka má obsahovat: |
|||
- Číslo položky (h3) |
|||
- Text "Obsah položky" (p) |
|||
- Barvu pozadí (přes CSS) |
|||
|
|||
### CSS požadavky: |
|||
|
|||
#### Grid Layout: |
|||
- Použijte `display: grid` |
|||
- Na desktopu: 3 sloupce se stejnou šířkou |
|||
- Na tabletu (max-width: 768px): 2 sloupce |
|||
- Na mobilu (max-width: 480px): 1 sloupec |
|||
- Mezery mezi položkami: 20px |
|||
|
|||
#### Pokročilé selektory: |
|||
Použijte tyto selektory pro obarvení položek: |
|||
- `.grid-item:nth-child(odd)` - liché položky -> světle modrá |
|||
- `.grid-item:nth-child(even)` - sudé položky -> světle zelená |
|||
- `.grid-item:first-child` - první položka -> zlatá |
|||
- `.grid-item:last-child` - poslední položka -> růžová |
|||
- `.grid-item:hover` - při najetí myší -> ztmavnout + zvětšit o 5% |
|||
|
|||
#### Extra výzva: |
|||
- Použijte `grid-template-areas` pro vytvoření speciálního layoutu, kde první položka zabírá 2 sloupce |
|||
|
|||
## 💡 Co se naučíte: |
|||
- CSS Grid základy (display: grid, grid-template-columns) |
|||
- Grid gaps (mezery) |
|||
- Responzivní grid s media queries |
|||
- Pokročilé CSS selektory (nth-child, first-child, last-child) |
|||
- CSS transformace (scale při hover) |
|||
|
|||
## 🔗 Užitečné odkazy: |
|||
- CSS Grid Guide: https://css-tricks.com/snippets/css/complete-guide-grid/ |
|||
- nth-child selector: https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child |
|||
|
|||
## ⏱️ Odhadovaný čas: 45-60 minut |
|||
@ -0,0 +1,18 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>AI 01 - CSS Grid Galerie</title> |
|||
<link rel="stylesheet" href="style.css"> |
|||
</head> |
|||
<body> |
|||
<h1>Galerie Obrázků</h1> |
|||
|
|||
<!-- TODO: Zde začněte pracovat --> |
|||
<!-- Vytvořte kontejner s třídou "grid-container" --> |
|||
<!-- Vytvořte 9 divů s třídou "grid-item" --> |
|||
<!-- Každý div má obsahovat h3 s číslem a p s textem --> |
|||
|
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,151 @@ |
|||
/* AI 01 - CSS Grid & Responzivní Layout - ŘEŠENÍ */ |
|||
|
|||
/* Základní styly pro body */ |
|||
body { |
|||
font-family: Arial, Helvetica, sans-serif; |
|||
margin: 0; |
|||
padding: 20px; |
|||
background-color: #f0f0f0; |
|||
} |
|||
|
|||
h1 { |
|||
text-align: center; |
|||
color: #333; |
|||
margin-bottom: 30px; |
|||
} |
|||
|
|||
/* Grid kontejner */ |
|||
.grid-container { |
|||
/* Display grid aktivuje grid layout */ |
|||
display: grid; |
|||
|
|||
/* Vytvoří 3 sloupce se stejnou šířkou (1fr = 1 fraction/část) */ |
|||
grid-template-columns: 1fr 1fr 1fr; |
|||
/* Alternativně: repeat(3, 1fr) - opakuje 1fr třikrát */ |
|||
|
|||
/* Gap vytváří mezery mezi grid položkami */ |
|||
gap: 20px; |
|||
/* Alternativně: grid-gap: 20px; (starší syntax) */ |
|||
|
|||
/* Maximální šířka kontejneru */ |
|||
max-width: 1200px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
/* Styling jednotlivých grid položek */ |
|||
.grid-item { |
|||
/* Základní styling */ |
|||
background-color: white; |
|||
padding: 30px; |
|||
border-radius: 10px; |
|||
text-align: center; |
|||
|
|||
/* Box shadow pro hezčí vzhled */ |
|||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
|||
|
|||
/* Transition pro plynulé animace */ |
|||
transition: transform 0.3s ease, box-shadow 0.3s ease; |
|||
} |
|||
|
|||
.grid-item h3 { |
|||
margin-top: 0; |
|||
color: #333; |
|||
} |
|||
|
|||
.grid-item p { |
|||
color: #666; |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
/* POKROČILÉ SELEKTORY */ |
|||
|
|||
/* nth-child(odd) = liché položky (1, 3, 5, 7, 9) */ |
|||
.grid-item:nth-child(odd) { |
|||
background-color: #e3f2fd; /* světle modrá */ |
|||
} |
|||
|
|||
/* nth-child(even) = sudé položky (2, 4, 6, 8) */ |
|||
.grid-item:nth-child(even) { |
|||
background-color: #e8f5e9; /* světle zelená */ |
|||
} |
|||
|
|||
/* first-child = první položka */ |
|||
.grid-item:first-child { |
|||
background-color: #ffd700; /* zlatá */ |
|||
/* Můžeme použít grid-column pro natažení přes 2 sloupce */ |
|||
grid-column: span 2; |
|||
} |
|||
|
|||
/* last-child = poslední položka */ |
|||
.grid-item:last-child { |
|||
background-color: #ffb6c1; /* růžová */ |
|||
} |
|||
|
|||
/* Hover efekt - při najetí myší */ |
|||
.grid-item:hover { |
|||
/* Transform scale zvětší element o 5% (1.05 = 105%) */ |
|||
transform: scale(1.05); |
|||
|
|||
/* Větší shadow při hover */ |
|||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); |
|||
|
|||
/* Můžeme také změnit kurzor */ |
|||
cursor: pointer; |
|||
} |
|||
|
|||
/* MEDIA QUERIES - Responzivita */ |
|||
|
|||
/* Tablet - maximální šířka 768px */ |
|||
@media only screen and (max-width: 768px) { |
|||
.grid-container { |
|||
/* Na tabletu jen 2 sloupce */ |
|||
grid-template-columns: 1fr 1fr; |
|||
/* Alternativně: repeat(2, 1fr) */ |
|||
} |
|||
|
|||
/* První položka už nezabírá 2 sloupce na tabletu */ |
|||
.grid-item:first-child { |
|||
grid-column: span 1; |
|||
} |
|||
} |
|||
|
|||
/* Mobil - maximální šířka 480px */ |
|||
@media only screen and (max-width: 480px) { |
|||
body { |
|||
padding: 10px; |
|||
} |
|||
|
|||
.grid-container { |
|||
/* Na mobilu jen 1 sloupec */ |
|||
grid-template-columns: 1fr; |
|||
|
|||
/* Menší gap na mobilu */ |
|||
gap: 15px; |
|||
} |
|||
|
|||
.grid-item { |
|||
/* Menší padding na mobilu */ |
|||
padding: 20px; |
|||
} |
|||
|
|||
h1 { |
|||
font-size: 24px; |
|||
} |
|||
} |
|||
|
|||
/* BONUS: Další užitečné selektory */ |
|||
|
|||
/* Každá třetí položka (3, 6, 9) */ |
|||
/* .grid-item:nth-child(3n) { |
|||
border: 3px solid #ff6b6b; |
|||
} */ |
|||
|
|||
/* Všechny položky kromě první */ |
|||
/* .grid-item:not(:first-child) { |
|||
opacity: 0.9; |
|||
} */ |
|||
|
|||
/* První 3 položky */ |
|||
/* .grid-item:nth-child(-n+3) { |
|||
font-weight: bold; |
|||
} */ |
|||
@ -0,0 +1,51 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>AI 01 - CSS Grid Galerie - ŘEŠENÍ</title> |
|||
<link rel="stylesheet" href="reseni.css"> |
|||
</head> |
|||
<body> |
|||
<h1>Galerie Obrázků</h1> |
|||
|
|||
<div class="grid-container"> |
|||
<div class="grid-item"> |
|||
<h3>Položka 1</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 2</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 3</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 4</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 5</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 6</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 7</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 8</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
<div class="grid-item"> |
|||
<h3>Položka 9</h3> |
|||
<p>Obsah položky</p> |
|||
</div> |
|||
</div> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,50 @@ |
|||
/* AI 01 - CSS Grid & Responzivní Layout */ |
|||
|
|||
/* Základní styly pro body */ |
|||
body { |
|||
font-family: Arial, Helvetica, sans-serif; |
|||
margin: 0; |
|||
padding: 20px; |
|||
background-color: #f0f0f0; |
|||
} |
|||
|
|||
h1 { |
|||
text-align: center; |
|||
color: #333; |
|||
margin-bottom: 30px; |
|||
} |
|||
|
|||
/* TODO: Zde začněte pracovat s Grid */ |
|||
|
|||
/* 1. Vytvořte .grid-container s display: grid */ |
|||
|
|||
|
|||
/* 2. Nastavte grid-template-columns pro 3 sloupce (desktop) */ |
|||
|
|||
|
|||
/* 3. Nastavte gap (mezery) mezi položkami na 20px */ |
|||
|
|||
|
|||
/* 4. Nastylujte .grid-item */ |
|||
|
|||
|
|||
/* 5. Použijte pokročilé selektory pro obarvení */ |
|||
/* .grid-item:nth-child(odd) - liché položky */ |
|||
|
|||
|
|||
/* .grid-item:nth-child(even) - sudé položky */ |
|||
|
|||
|
|||
/* .grid-item:first-child - první položka */ |
|||
|
|||
|
|||
/* .grid-item:last-child - poslední položka */ |
|||
|
|||
|
|||
/* .grid-item:hover - hover efekt */ |
|||
|
|||
|
|||
/* 6. Media query pro tablet (max-width: 768px) - 2 sloupce */ |
|||
|
|||
|
|||
/* 7. Media query pro mobil (max-width: 480px) - 1 sloupec */ |
|||
@ -0,0 +1,221 @@ |
|||
# AI 02 - Sémantické HTML5 & CSS Positioning |
|||
|
|||
## 🎯 Cíl projektu |
|||
|
|||
Naučit se používat **sémantické HTML5 elementy** a **CSS positioning** (absolute, relative, fixed, sticky), které jsou důležité pro moderní webový vývoj a Bootstrap. |
|||
|
|||
## 📋 Co se naučíte |
|||
|
|||
- **Sémantické HTML5 elementy** - `<nav>`, `<main>`, `<section>`, `<article>`, `<aside>`, `<footer>` |
|||
- **CSS Positioning** - `fixed`, `sticky`, `relative`, `absolute` |
|||
- **CSS jednotky** - `rem`, `em`, `vh`, `vw` (ne jen `px`!) |
|||
- **Strukturu moderní webové stránky** |
|||
- **Z-index** - vrstvení elementů |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- **ZADANI.md** - detailní zadání projektu |
|||
- **index.html** - startovací HTML (s TODO komentáři) |
|||
- **style.css** - CSS šablona (s TODO komentáři) |
|||
- **reseni.html** - kompletní řešení |
|||
- **reseni.css** - CSS s podrobnými komentáři |
|||
|
|||
## 🚀 Jak pracovat s projektem |
|||
|
|||
### Krok 1: Přečtěte si ZADANI.md |
|||
- Pochopte, jaké elementy máte vytvořit |
|||
- Projděte si požadavky na positioning |
|||
|
|||
### Krok 2: Vytvořte strukturu stránky |
|||
Vytvořte **portfolio stránku** s těmito sekcemi: |
|||
1. **`<nav>`** - fixní navigace nahoře |
|||
2. **`<header>`** - úvodní sekce (hero) |
|||
3. **`<main>`** s `<section>` elementy: |
|||
- O mně |
|||
- Projekty (s `<article>` elementy) |
|||
- Kontakt |
|||
4. **`<aside>`** - sticky boční panel |
|||
5. **`<footer>`** - zápatí |
|||
|
|||
### Krok 3: Aplikujte CSS Positioning |
|||
|
|||
**Fixed navigace:** |
|||
```css |
|||
nav { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
z-index: 1000; /* nad ostatními elementy */ |
|||
} |
|||
``` |
|||
|
|||
**Sticky aside:** |
|||
```css |
|||
aside { |
|||
position: sticky; |
|||
top: 100px; /* od vrcholu po scrollování */ |
|||
} |
|||
``` |
|||
|
|||
**Absolute badge:** |
|||
```css |
|||
.project { |
|||
position: relative; /* kontejner */ |
|||
} |
|||
|
|||
.badge { |
|||
position: absolute; |
|||
top: 10px; |
|||
right: 10px; |
|||
} |
|||
``` |
|||
|
|||
### Krok 4: Použijte moderní jednotky |
|||
```css |
|||
/* ❌ Staré (pouze px) */ |
|||
font-size: 16px; |
|||
padding: 20px; |
|||
height: 600px; |
|||
|
|||
/* ✅ Moderní (rem, em, vh) */ |
|||
font-size: 1rem; /* 16px (skaluje s root) */ |
|||
padding: 1.25rem; /* 20px */ |
|||
height: 60vh; /* 60% výšky viewportu */ |
|||
``` |
|||
|
|||
## 💡 Klíčové koncepty |
|||
|
|||
### Sémantické HTML5 elementy: |
|||
|
|||
```html |
|||
<!-- ✅ SPRÁVNĚ - sémantické --> |
|||
<nav> |
|||
<a href="#home">Domů</a> |
|||
</nav> |
|||
|
|||
<main> |
|||
<section id="about"> |
|||
<h2>O mně</h2> |
|||
<article>...</article> |
|||
</section> |
|||
</main> |
|||
|
|||
<aside>Boční panel</aside> |
|||
|
|||
<footer>© 2025</footer> |
|||
|
|||
<!-- ❌ ŠPATNĚ - nesémantické --> |
|||
<div class="nav"> |
|||
<a href="#home">Domů</a> |
|||
</div> |
|||
|
|||
<div class="main"> |
|||
<div class="section">...</div> |
|||
</div> |
|||
``` |
|||
|
|||
### CSS Positioning: |
|||
|
|||
**Static (výchozí):** |
|||
- Normální tok dokumentu |
|||
- Nelze posunout pomocí top/left/right/bottom |
|||
|
|||
**Relative:** |
|||
- Relativní k původní pozici |
|||
- Nezabírá místo v místě posunutí |
|||
```css |
|||
.element { |
|||
position: relative; |
|||
top: 20px; /* posune se 20px dolů od původní pozice */ |
|||
} |
|||
``` |
|||
|
|||
**Absolute:** |
|||
- Absolutní k nejbližšímu pozicovanému rodiči |
|||
- Vyjmut z normálního toku |
|||
```css |
|||
.parent { |
|||
position: relative; /* !! důležité !! */ |
|||
} |
|||
|
|||
.child { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
} |
|||
``` |
|||
|
|||
**Fixed:** |
|||
- Fixní k viewportu |
|||
- Zůstává na místě při scrollování |
|||
```css |
|||
.navbar { |
|||
position: fixed; |
|||
top: 0; |
|||
width: 100%; |
|||
} |
|||
``` |
|||
|
|||
**Sticky:** |
|||
- Kombinace relative a fixed |
|||
- Sticky když dojedete na určitou pozici |
|||
```css |
|||
.sidebar { |
|||
position: sticky; |
|||
top: 20px; /* zůstane 20px od vrcholu */ |
|||
} |
|||
``` |
|||
|
|||
### CSS Jednotky: |
|||
|
|||
| Jednotka | Popis | Použití | |
|||
|----------|-------|---------| |
|||
| `px` | Pixel (absolutní) | Borders, malé hodnoty | |
|||
| `rem` | Relativní k root font-size | Font sizes, paddingy | |
|||
| `em` | Relativní k parent font-size | Specifické případy | |
|||
| `%` | Procenta z parenta | Šířky, výšky | |
|||
| `vh` | 1% výšky viewportu | Full-screen sekce | |
|||
| `vw` | 1% šířky viewportu | Responzivní šířky | |
|||
|
|||
## ⚠️ Časté chyby |
|||
|
|||
❌ **Absolute element není kde má být** |
|||
→ Zapomněli jste `position: relative` na rodiče |
|||
|
|||
❌ **Fixed navigace překrývá obsah** |
|||
→ Přidejte `padding-top` na body nebo main |
|||
|
|||
❌ **Sticky nefunguje** |
|||
→ Zkontrolujte, že má rodič dostatek výšky na scrollování |
|||
|
|||
❌ **Z-index nefunguje** |
|||
→ Funguje pouze na pozicovaných elementech (ne static) |
|||
|
|||
## 🎓 Hodnocení (15 bodů) |
|||
|
|||
- **Sémantická struktura** (4b) - správné použití nav, main, section, article, aside, footer |
|||
- **Position: fixed, sticky** (3b) - fixní navigace, sticky aside |
|||
- **Position: relative, absolute** (3b) - badge na projektu |
|||
- **CSS jednotky (rem, em, vh)** (2b) - použití místo px |
|||
- **Responzivita** (3b) - aside zmizí na mobilu, funguje na všech zařízeních |
|||
|
|||
## 🔗 Užitečné odkazy |
|||
|
|||
- [HTML5 Semantic Elements - W3Schools](https://www.w3schools.com/html/html5_semantic_elements.asp) |
|||
- [CSS Position - CSS Tricks](https://css-tricks.com/almanac/properties/p/position/) |
|||
- [CSS Units - MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units) |
|||
|
|||
## ⏱️ Odhadovaný čas |
|||
|
|||
**60-90 minut** |
|||
|
|||
## 🎯 Po dokončení |
|||
|
|||
Po dokončení tohoto projektu budete rozumět: |
|||
- Sémantické HTML5 (důležité pro SEO a přístupnost) |
|||
- Všem typům CSS positioning |
|||
- Moderním CSS jednotkám (rem, vh, vw) |
|||
- Jak vytvořit sticky/fixed elementy |
|||
|
|||
➡️ **Další projekt:** AI 03 - Pokročilá Validace Formulářů s JavaScript |
|||
@ -0,0 +1,67 @@ |
|||
# AI 02 - Sémantické HTML5 & CSS Positioning |
|||
|
|||
## 🎯 Cíl projektu |
|||
Naučit se používat sémantické HTML5 elementy a CSS positioning (absolute, relative, fixed, sticky), které jsou důležité pro moderní webový vývoj a Bootstrap. |
|||
|
|||
## 📝 Zadání |
|||
|
|||
Vytvořte jednoduchou osobní portfolio stránku s následujícími sekcemi: |
|||
|
|||
### HTML požadavky - Použijte SÉMANTICKÉ elementy: |
|||
|
|||
1. **`<nav>`** - Navigační menu (fixní nahoře) |
|||
- Logo (h2) |
|||
- 4 odkazy: Domů, O mně, Projekty, Kontakt |
|||
|
|||
2. **`<header>`** - Úvodní sekce |
|||
- Hlavní nadpis s vaším jménem (h1) |
|||
- Podnadpis s profesí (p) |
|||
- Tlačítko "Více o mně" |
|||
|
|||
3. **`<main>`** - Hlavní obsah stránky obsahující: |
|||
|
|||
**`<section id="about">`** - O mně |
|||
- Nadpis (h2) |
|||
- 2-3 odstavce textu (p) |
|||
- Obrázek (placeholder: https://via.placeholder.com/300) |
|||
|
|||
**`<section id="projects">`** - Projekty |
|||
- Nadpis (h2) |
|||
- 3x `<article>` s projekty |
|||
- Každý article má: h3 (název), p (popis), obrázek |
|||
|
|||
**`<section id="contact">`** - Kontakt |
|||
- Nadpis (h2) |
|||
- Formulář (jméno, email, zpráva, tlačítko) |
|||
|
|||
4. **`<footer>`** - Zápatí |
|||
- Copyright text |
|||
- Sociální sítě odkazy |
|||
|
|||
5. **`<aside>`** - Boční panel (sticky) |
|||
- "Rychlé info" |
|||
- Email, Telefon, Lokace |
|||
|
|||
### CSS Positioning požadavky: |
|||
|
|||
1. **`position: fixed`** - Navigace zůstává nahoře při scrollování |
|||
2. **`position: sticky`** - Aside zůstává viditelný při scrollování (od určitého bodu) |
|||
3. **`position: relative`** - Kontejner pro absolutně pozicované elementy |
|||
4. **`position: absolute`** - Badge "NOVÝ!" u jednoho projektu |
|||
|
|||
### Design požadavky: |
|||
- Použijte jednotky: rem, em, vh (ne jen px!) |
|||
- Přidejte barvy a odstupy pro přehlednost |
|||
- Responzivní (aside zmizí na mobilu) |
|||
|
|||
## 💡 Co se naučíte: |
|||
- Sémantické HTML5 elementy (nav, main, section, article, aside) |
|||
- CSS Positioning (fixed, sticky, relative, absolute) |
|||
- CSS jednotky (rem, em, vh, vw) |
|||
- Strukturu moderní webové stránky |
|||
|
|||
## 🔗 Užitečné odkazy: |
|||
- HTML5 Semantic Elements: https://www.w3schools.com/html/html5_semantic_elements.asp |
|||
- CSS Position: https://css-tricks.com/almanac/properties/p/position/ |
|||
|
|||
## ⏱️ Odhadovaný čas: 60-90 minut |
|||
@ -0,0 +1,36 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>AI 02 - Portfolio</title> |
|||
<link rel="stylesheet" href="style.css"> |
|||
</head> |
|||
<body> |
|||
<!-- TODO: Začněte zde --> |
|||
|
|||
<!-- 1. Vytvořte <nav> s navigací --> |
|||
|
|||
|
|||
<!-- 2. Vytvořte <header> s úvodní sekcí --> |
|||
|
|||
|
|||
<!-- 3. Vytvořte <main> s hlavním obsahem --> |
|||
|
|||
<!-- 3a. <section id="about"> - O mně --> |
|||
|
|||
|
|||
<!-- 3b. <section id="projects"> - Projekty (obsahuje 3x <article>) --> |
|||
|
|||
|
|||
<!-- 3c. <section id="contact"> - Kontakt s formulářem --> |
|||
|
|||
|
|||
<!-- 4. Vytvořte <aside> s rychlými informacemi (bude sticky) --> |
|||
|
|||
|
|||
<!-- 5. Vytvořte <footer> se zápatím --> |
|||
|
|||
|
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,422 @@ |
|||
/* AI 02 - Sémantické HTML5 & CSS Positioning - ŘEŠENÍ */ |
|||
|
|||
/* ============================================ |
|||
ZÁKLADNÍ RESET A NASTAVENÍ |
|||
============================================ */ |
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
/* Root font-size pro REM jednotky */ |
|||
html { |
|||
font-size: 16px; /* 1rem = 16px */ |
|||
scroll-behavior: smooth; /* Plynulé scrollování k kotevním odkazům */ |
|||
} |
|||
|
|||
body { |
|||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|||
line-height: 1.6; |
|||
color: #333; |
|||
/* Padding-top kvůli fixní navigaci */ |
|||
padding-top: 4rem; |
|||
} |
|||
|
|||
/* ============================================ |
|||
NAVIGACE - position: fixed |
|||
============================================ */ |
|||
nav { |
|||
/* FIXED positioning - zůstává na stejném místě při scrollování */ |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
width: 100%; |
|||
|
|||
background-color: #2c3e50; |
|||
padding: 1rem 0; |
|||
z-index: 1000; /* Vysoký z-index aby byl nav nad vším ostatním */ |
|||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.nav-container { |
|||
max-width: 1200px; |
|||
margin: 0 auto; |
|||
padding: 0 2rem; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.logo { |
|||
color: white; |
|||
font-size: 1.5rem; /* 24px (16px * 1.5) */ |
|||
margin: 0; |
|||
} |
|||
|
|||
.nav-links { |
|||
display: flex; |
|||
list-style: none; |
|||
gap: 2rem; /* Mezery mezi položkami */ |
|||
} |
|||
|
|||
.nav-links a { |
|||
color: white; |
|||
text-decoration: none; |
|||
font-size: 1rem; |
|||
transition: color 0.3s ease; |
|||
} |
|||
|
|||
.nav-links a:hover { |
|||
color: #3498db; |
|||
} |
|||
|
|||
/* ============================================ |
|||
HEADER - Úvodní sekce |
|||
============================================ */ |
|||
header { |
|||
/* vh jednotka = viewport height (výška viewportu) */ |
|||
height: 100vh; /* Celá výška obrazovky */ |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
text-align: center; |
|||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|||
color: white; |
|||
} |
|||
|
|||
header h1 { |
|||
font-size: 3rem; /* 48px */ |
|||
margin-bottom: 1rem; |
|||
animation: fadeInDown 1s ease; |
|||
} |
|||
|
|||
.subtitle { |
|||
font-size: 1.5rem; /* 24px */ |
|||
margin-bottom: 2rem; |
|||
opacity: 0.9; |
|||
} |
|||
|
|||
.btn { |
|||
display: inline-block; |
|||
padding: 0.75rem 2rem; |
|||
background-color: white; |
|||
color: #667eea; |
|||
text-decoration: none; |
|||
border-radius: 30px; |
|||
font-weight: bold; |
|||
transition: transform 0.3s ease, box-shadow 0.3s ease; |
|||
} |
|||
|
|||
.btn:hover { |
|||
transform: translateY(-3px); |
|||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); |
|||
} |
|||
|
|||
/* ============================================ |
|||
MAIN - Hlavní obsah |
|||
============================================ */ |
|||
main { |
|||
max-width: 1200px; |
|||
margin: 0 auto; |
|||
padding: 0 2rem; |
|||
/* Margin-right pro aside (boční panel) */ |
|||
margin-right: 320px; |
|||
} |
|||
|
|||
/* ============================================ |
|||
SECTION - Jednotlivé sekce |
|||
============================================ */ |
|||
section { |
|||
padding: 4rem 0; /* rem jednotka (relativní k root font-size) */ |
|||
border-bottom: 1px solid #eee; |
|||
} |
|||
|
|||
section h2 { |
|||
font-size: 2.5rem; /* 40px */ |
|||
margin-bottom: 2rem; |
|||
color: #2c3e50; |
|||
text-align: center; |
|||
} |
|||
|
|||
/* O MNĚ sekce */ |
|||
#about .about-content { |
|||
display: flex; |
|||
gap: 3rem; |
|||
align-items: center; |
|||
} |
|||
|
|||
#about img { |
|||
border-radius: 10px; |
|||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.about-text p { |
|||
margin-bottom: 1rem; |
|||
font-size: 1.1rem; |
|||
text-align: justify; |
|||
} |
|||
|
|||
/* PROJEKTY sekce */ |
|||
#projects .projects-grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); |
|||
gap: 2rem; |
|||
margin-top: 2rem; |
|||
} |
|||
|
|||
/* ============================================ |
|||
ARTICLE - Projekt karty |
|||
============================================ */ |
|||
article.project-card { |
|||
background: white; |
|||
border-radius: 10px; |
|||
overflow: hidden; |
|||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); |
|||
transition: transform 0.3s ease; |
|||
|
|||
/* RELATIVE positioning - vytváří kontext pro absolute positioning */ |
|||
position: relative; |
|||
} |
|||
|
|||
article.project-card:hover { |
|||
transform: translateY(-10px); |
|||
} |
|||
|
|||
article.project-card img { |
|||
width: 100%; |
|||
height: auto; |
|||
display: block; |
|||
} |
|||
|
|||
article.project-card h3 { |
|||
padding: 1rem; |
|||
font-size: 1.5rem; |
|||
color: #2c3e50; |
|||
} |
|||
|
|||
article.project-card p { |
|||
padding: 0 1rem 1.5rem; |
|||
color: #666; |
|||
line-height: 1.6; |
|||
} |
|||
|
|||
/* Badge "NOVÝ!" - position: absolute */ |
|||
.badge { |
|||
/* ABSOLUTE positioning - pozicuje se relativně k prvnímu parent elementu s position: relative */ |
|||
position: absolute; |
|||
top: 1rem; |
|||
right: 1rem; |
|||
|
|||
background-color: #e74c3c; |
|||
color: white; |
|||
padding: 0.5rem 1rem; |
|||
border-radius: 20px; |
|||
font-weight: bold; |
|||
font-size: 0.875rem; /* 14px */ |
|||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); |
|||
} |
|||
|
|||
/* KONTAKT sekce */ |
|||
#contact { |
|||
max-width: 600px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
.contact-form { |
|||
margin-top: 2rem; |
|||
} |
|||
|
|||
.form-group { |
|||
margin-bottom: 1.5rem; |
|||
} |
|||
|
|||
.form-group label { |
|||
display: block; |
|||
margin-bottom: 0.5rem; |
|||
font-weight: bold; |
|||
color: #2c3e50; |
|||
} |
|||
|
|||
.form-group input, |
|||
.form-group textarea { |
|||
width: 100%; |
|||
padding: 0.75rem; |
|||
border: 2px solid #ddd; |
|||
border-radius: 5px; |
|||
font-size: 1rem; |
|||
font-family: inherit; |
|||
transition: border-color 0.3s ease; |
|||
} |
|||
|
|||
.form-group input:focus, |
|||
.form-group textarea:focus { |
|||
outline: none; |
|||
border-color: #667eea; |
|||
} |
|||
|
|||
/* ============================================ |
|||
ASIDE - Boční panel, position: sticky |
|||
============================================ */ |
|||
aside { |
|||
/* STICKY positioning - chová se jako relative, dokud nedosáhne určitého bodu, pak se chová jako fixed */ |
|||
position: sticky; |
|||
top: 5rem; /* Odshora (pod navigací) */ |
|||
|
|||
/* Umístění vpravo */ |
|||
position: fixed; |
|||
right: 2rem; |
|||
top: 6rem; |
|||
width: 250px; |
|||
|
|||
background-color: #f8f9fa; |
|||
padding: 1.5rem; |
|||
border-radius: 10px; |
|||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
aside h3 { |
|||
color: #2c3e50; |
|||
margin-bottom: 1.5rem; |
|||
font-size: 1.25rem; |
|||
} |
|||
|
|||
.info-item { |
|||
margin-bottom: 1rem; |
|||
padding-bottom: 1rem; |
|||
border-bottom: 1px solid #ddd; |
|||
} |
|||
|
|||
.info-item:last-child { |
|||
border-bottom: none; |
|||
margin-bottom: 0; |
|||
padding-bottom: 0; |
|||
} |
|||
|
|||
.info-item strong { |
|||
display: block; |
|||
color: #667eea; |
|||
margin-bottom: 0.25rem; |
|||
font-size: 0.875rem; |
|||
} |
|||
|
|||
.info-item p { |
|||
color: #555; |
|||
margin: 0; |
|||
font-size: 0.875rem; |
|||
} |
|||
|
|||
/* ============================================ |
|||
FOOTER - Zápatí |
|||
============================================ */ |
|||
footer { |
|||
background-color: #2c3e50; |
|||
color: white; |
|||
text-align: center; |
|||
padding: 2rem; |
|||
margin-top: 4rem; |
|||
margin-right: 320px; /* Kvůli aside */ |
|||
} |
|||
|
|||
footer p { |
|||
margin-bottom: 1rem; |
|||
} |
|||
|
|||
.social-links { |
|||
display: flex; |
|||
justify-content: center; |
|||
gap: 2rem; |
|||
} |
|||
|
|||
.social-links a { |
|||
color: white; |
|||
text-decoration: none; |
|||
transition: color 0.3s ease; |
|||
} |
|||
|
|||
.social-links a:hover { |
|||
color: #3498db; |
|||
} |
|||
|
|||
/* ============================================ |
|||
ANIMACE |
|||
============================================ */ |
|||
@keyframes fadeInDown { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(-20px); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
/* ============================================ |
|||
MEDIA QUERIES - Responzivita |
|||
============================================ */ |
|||
@media screen and (max-width: 768px) { |
|||
/* Schovat aside na menších obrazovkách */ |
|||
aside { |
|||
display: none; |
|||
} |
|||
|
|||
/* Odstranit margin-right z main a footer */ |
|||
main, |
|||
footer { |
|||
margin-right: 0; |
|||
} |
|||
|
|||
/* Úprava navigace */ |
|||
.nav-container { |
|||
flex-direction: column; |
|||
gap: 1rem; |
|||
} |
|||
|
|||
.nav-links { |
|||
gap: 1rem; |
|||
} |
|||
|
|||
/* Zmenšit font sizes */ |
|||
header h1 { |
|||
font-size: 2rem; |
|||
} |
|||
|
|||
.subtitle { |
|||
font-size: 1.2rem; |
|||
} |
|||
|
|||
section h2 { |
|||
font-size: 2rem; |
|||
} |
|||
|
|||
/* O mně - stack na mobilu */ |
|||
#about .about-content { |
|||
flex-direction: column; |
|||
} |
|||
|
|||
/* Kontakt - celá šířka */ |
|||
#contact { |
|||
max-width: 100%; |
|||
} |
|||
} |
|||
|
|||
@media screen and (max-width: 480px) { |
|||
body { |
|||
padding-top: 6rem; /* Více místa pro higher nav */ |
|||
} |
|||
|
|||
main { |
|||
padding: 0 1rem; |
|||
} |
|||
|
|||
section { |
|||
padding: 2rem 0; |
|||
} |
|||
|
|||
.projects-grid { |
|||
grid-template-columns: 1fr; |
|||
} |
|||
} |
|||
@ -0,0 +1,119 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>AI 02 - Portfolio - ŘEŠENÍ</title> |
|||
<link rel="stylesheet" href="reseni.css"> |
|||
</head> |
|||
<body> |
|||
<!-- NAVIGACE - Sémantický element pro navigaci --> |
|||
<nav> |
|||
<div class="nav-container"> |
|||
<h2 class="logo">MůjWeb</h2> |
|||
<ul class="nav-links"> |
|||
<li><a href="#home">Domů</a></li> |
|||
<li><a href="#about">O mně</a></li> |
|||
<li><a href="#projects">Projekty</a></li> |
|||
<li><a href="#contact">Kontakt</a></li> |
|||
</ul> |
|||
</div> |
|||
</nav> |
|||
|
|||
<!-- HEADER - Úvodní hlavička stránky --> |
|||
<header id="home"> |
|||
<h1>Jan Novák</h1> |
|||
<p class="subtitle">Web Developer & Designer</p> |
|||
<a href="#about" class="btn">Více o mně</a> |
|||
</header> |
|||
|
|||
<!-- MAIN - Hlavní obsah stránky --> |
|||
<main> |
|||
<!-- SECTION - Sémantický element pro sekci stránky --> |
|||
<section id="about"> |
|||
<h2>O mně</h2> |
|||
<div class="about-content"> |
|||
<img src="https://via.placeholder.com/300" alt="Profilový obrázek"> |
|||
<div class="about-text"> |
|||
<p>Jsem web developer s vášní pro vytváření moderních a responzivních webových stránek. Specializuji se na frontend technologie jako HTML, CSS, JavaScript a Bootstrap.</p> |
|||
<p>Ve volném čase se rád věnuji učení nových technologií a pracuji na open-source projektech. Mým cílem je vytvářet webové aplikace, které jsou nejen funkční, ale i esteticky příjemné.</p> |
|||
<p>Pokud hledáte někoho, kdo vašemu projektu dodá profesionální vzhled a špičkovou funkcionalitu, jste na správném místě!</p> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<!-- SECTION - Projekty --> |
|||
<section id="projects"> |
|||
<h2>Moje Projekty</h2> |
|||
<div class="projects-grid"> |
|||
<!-- ARTICLE - Sémantický element pro samostatný obsah --> |
|||
<article class="project-card"> |
|||
<span class="badge">NOVÝ!</span> |
|||
<img src="https://via.placeholder.com/350x200" alt="Projekt 1"> |
|||
<h3>E-shop s oblečením</h3> |
|||
<p>Moderní e-commerce stránka s košíkem, filtrováním produktů a responzivním designem. Použité technologie: HTML, CSS, JavaScript.</p> |
|||
</article> |
|||
|
|||
<article class="project-card"> |
|||
<img src="https://via.placeholder.com/350x200" alt="Projekt 2"> |
|||
<h3>Portfolio fotografie</h3> |
|||
<p>Elegantní portfolio pro fotografa s galerií, lightboxem a plynulými animacemi. Optimalizováno pro mobily.</p> |
|||
</article> |
|||
|
|||
<article class="project-card"> |
|||
<img src="https://via.placeholder.com/350x200" alt="Projekt 3"> |
|||
<h3>Firemní web</h3> |
|||
<p>Profesionální prezentace firmy s informacemi o službách, referencemi a kontaktním formulářem.</p> |
|||
</article> |
|||
</div> |
|||
</section> |
|||
|
|||
<!-- SECTION - Kontakt --> |
|||
<section id="contact"> |
|||
<h2>Kontaktujte mě</h2> |
|||
<form class="contact-form"> |
|||
<div class="form-group"> |
|||
<label for="name">Jméno:</label> |
|||
<input type="text" id="name" name="name" required> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="email">Email:</label> |
|||
<input type="email" id="email" name="email" required> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="message">Zpráva:</label> |
|||
<textarea id="message" name="message" rows="5" required></textarea> |
|||
</div> |
|||
<button type="submit" class="btn">Odeslat zprávu</button> |
|||
</form> |
|||
</section> |
|||
</main> |
|||
|
|||
<!-- ASIDE - Boční panel s rychlými informacemi --> |
|||
<aside> |
|||
<h3>Rychlé info</h3> |
|||
<div class="info-item"> |
|||
<strong>Email:</strong> |
|||
<p>jan.novak@email.cz</p> |
|||
</div> |
|||
<div class="info-item"> |
|||
<strong>Telefon:</strong> |
|||
<p>+420 123 456 789</p> |
|||
</div> |
|||
<div class="info-item"> |
|||
<strong>Lokace:</strong> |
|||
<p>Praha, Česká republika</p> |
|||
</div> |
|||
</aside> |
|||
|
|||
<!-- FOOTER - Zápatí stránky --> |
|||
<footer> |
|||
<p>© 2025 Jan Novák. Všechna práva vyhrazena.</p> |
|||
<div class="social-links"> |
|||
<a href="#">Facebook</a> |
|||
<a href="#">LinkedIn</a> |
|||
<a href="#">GitHub</a> |
|||
</div> |
|||
</footer> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,54 @@ |
|||
/* AI 02 - Sémantické HTML5 & CSS Positioning */ |
|||
|
|||
/* Základní reset a nastavení */ |
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
/* TODO: Nastavte root font-size pro rem jednotky */ |
|||
html { |
|||
/* 1rem = 16px (výchozí) */ |
|||
} |
|||
|
|||
body { |
|||
font-family: Arial, Helvetica, sans-serif; |
|||
line-height: 1.6; |
|||
color: #333; |
|||
} |
|||
|
|||
/* TODO: NAVIGACE - position: fixed */ |
|||
/* nav {} */ |
|||
|
|||
|
|||
/* TODO: HEADER - úvodní sekce */ |
|||
/* header {} */ |
|||
|
|||
|
|||
/* TODO: MAIN - hlavní obsah */ |
|||
/* main {} */ |
|||
|
|||
|
|||
/* TODO: SECTION - jednotlivé sekce */ |
|||
/* section {} */ |
|||
|
|||
|
|||
/* TODO: ARTICLE - projekty */ |
|||
/* article {} */ |
|||
|
|||
|
|||
/* TODO: ASIDE - boční panel, position: sticky */ |
|||
/* aside {} */ |
|||
|
|||
|
|||
/* TODO: FOOTER - zápatí */ |
|||
/* footer {} */ |
|||
|
|||
|
|||
/* TODO: POSITIONING */ |
|||
/* Vytvořte badge "NOVÝ!" s position: absolute */ |
|||
|
|||
|
|||
/* TODO: MEDIA QUERIES */ |
|||
/* Na mobilu (max-width: 768px) schovat aside */ |
|||
@ -0,0 +1,301 @@ |
|||
# AI 03 - Pokročilá Validace Formulářů s JavaScript |
|||
|
|||
## 🎯 Cíl projektu |
|||
|
|||
Naučit se **pokročilou práci s formuláři** a **JavaScript validací**. Bootstrap má vestavěné validační třídy, takže je důležité rozumět, jak validace funguje "pod kapotou". |
|||
|
|||
## 📋 Co se naučíte |
|||
|
|||
- **addEventListener** - moderní přístup místo inline `onclick` |
|||
- **Form validation** v JavaScriptu |
|||
- **RegEx** (regulární výrazy) pro validaci formátů |
|||
- **DOM manipulace** - `classList`, `innerHTML`, `textContent` |
|||
- **Event handling** - `input`, `submit` events |
|||
- **Real-time feedback** - validace při psaní |
|||
- **Visual feedback** - červená/zelená border, ikony, zprávy |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- **ZADANI.md** - detailní zadání s požadavky na validaci |
|||
- **index.html** - startovací HTML (s TODO komentáři) |
|||
- **style.css** - CSS šablona |
|||
- **script.js** - JavaScript šablona (s TODO komentáři) |
|||
- **reseni.html** - kompletní řešení |
|||
- **reseni.css** - CSS s komentáři |
|||
- **reseni.js** - JavaScript s podrobnými komentáři |
|||
|
|||
## 🚀 Jak pracovat s projektem |
|||
|
|||
### Krok 1: Přečtěte si ZADANI.md |
|||
- Pochopte požadavky na validaci každého pole |
|||
- Projděte si příklady kódu |
|||
|
|||
### Krok 2: Vytvořte registrační formulář |
|||
|
|||
Formulář obsahuje: |
|||
1. **Jméno** - min 3 znaky, jen písmena |
|||
2. **Email** - validní formát |
|||
3. **Heslo** - min 8 znaků, velké písmeno, číslo, speciální znak |
|||
4. **Potvrzení hesla** - musí se shodovat |
|||
5. **Věk** - 18-120 |
|||
6. **Souhlas s podmínkami** - checkbox |
|||
|
|||
### Krok 3: Implementujte addEventListener |
|||
|
|||
❌ **STARÝ způsob (inline):** |
|||
```html |
|||
<input type="text" onchange="validateName()"> |
|||
``` |
|||
|
|||
✅ **NOVÝ způsob (addEventListener):** |
|||
```html |
|||
<input type="text" id="jmeno"> |
|||
``` |
|||
|
|||
```javascript |
|||
document.getElementById("jmeno").addEventListener("input", validateName); |
|||
``` |
|||
|
|||
### Krok 4: Vytvořte validační funkce |
|||
|
|||
```javascript |
|||
// Validace jména |
|||
function validateName() { |
|||
const nameInput = document.getElementById("jmeno"); |
|||
const nameValue = nameInput.value; |
|||
const errorElement = document.getElementById("jmeno-error"); |
|||
|
|||
// Kontrola délky |
|||
if (nameValue.length < 3) { |
|||
showError(nameInput, errorElement, "Jméno musí mít alespoň 3 znaky"); |
|||
return false; |
|||
} |
|||
|
|||
// Kontrola pouze písmen (RegEx) |
|||
const nameRegex = /^[a-zA-ZáčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ\s]+$/; |
|||
if (!nameRegex.test(nameValue)) { |
|||
showError(nameInput, errorElement, "Jméno může obsahovat pouze písmena"); |
|||
return false; |
|||
} |
|||
|
|||
// Vše OK |
|||
showSuccess(nameInput, errorElement); |
|||
return true; |
|||
} |
|||
|
|||
// Helper funkce |
|||
function showError(input, errorElement, message) { |
|||
input.classList.add("error"); |
|||
input.classList.remove("success"); |
|||
errorElement.textContent = message; |
|||
errorElement.style.display = "block"; |
|||
} |
|||
|
|||
function showSuccess(input, errorElement) { |
|||
input.classList.remove("error"); |
|||
input.classList.add("success"); |
|||
errorElement.style.display = "none"; |
|||
} |
|||
``` |
|||
|
|||
## 💡 Klíčové koncepty |
|||
|
|||
### addEventListener vs onclick: |
|||
|
|||
```javascript |
|||
// ✅ MODERNÍ - addEventListener (doporučený) |
|||
const button = document.getElementById("myButton"); |
|||
button.addEventListener("click", function() { |
|||
console.log("Kliknuto!"); |
|||
}); |
|||
|
|||
// ❌ STARŠÍ - inline onclick |
|||
// <button onclick="handleClick()">Click</button> |
|||
``` |
|||
|
|||
**Výhody addEventListener:** |
|||
- Více listenerů na jeden element |
|||
- Oddělení HTML a JavaScriptu |
|||
- Možnost odstranit listener |
|||
- Lepší čitelnost |
|||
|
|||
### RegEx příklady: |
|||
|
|||
```javascript |
|||
// Email |
|||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
|||
emailRegex.test("user@email.com"); // true |
|||
|
|||
// Heslo (min 8 znaků, velké, malé, číslo, spec. znak) |
|||
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; |
|||
|
|||
// Pouze písmena (včetně diakritiky) |
|||
const nameRegex = /^[a-zA-ZáčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ\s]+$/; |
|||
|
|||
// Telefon (CZ formát) |
|||
const phoneRegex = /^(\+420)?[0-9]{9}$/; |
|||
``` |
|||
|
|||
### classList manipulace: |
|||
|
|||
```javascript |
|||
// Přidání třídy |
|||
element.classList.add("error"); |
|||
|
|||
// Odebrání třídy |
|||
element.classList.remove("error"); |
|||
|
|||
// Toggle (přidá/odebere) |
|||
element.classList.toggle("active"); |
|||
|
|||
// Kontrola existence |
|||
if (element.classList.contains("error")) { |
|||
// ... |
|||
} |
|||
|
|||
// Více tříd najednou |
|||
element.classList.add("error", "shake"); |
|||
``` |
|||
|
|||
### Event types: |
|||
|
|||
```javascript |
|||
// Při každé změně (real-time) |
|||
input.addEventListener("input", validateName); |
|||
|
|||
// Po opuštění pole |
|||
input.addEventListener("blur", validateName); |
|||
|
|||
// Při odeslání formuláře |
|||
form.addEventListener("submit", function(e) { |
|||
e.preventDefault(); // zabrání odeslání |
|||
// validace... |
|||
}); |
|||
``` |
|||
|
|||
## 🎯 Úplný příklad - Email validace |
|||
|
|||
```html |
|||
<!-- HTML --> |
|||
<div class="form-group"> |
|||
<label for="email">Email:</label> |
|||
<input type="email" id="email" class="form-control"> |
|||
<span class="error-message" id="email-error"></span> |
|||
</div> |
|||
``` |
|||
|
|||
```javascript |
|||
// JavaScript |
|||
document.getElementById("email").addEventListener("input", validateEmail); |
|||
|
|||
function validateEmail() { |
|||
const emailInput = document.getElementById("email"); |
|||
const emailValue = emailInput.value; |
|||
const errorElement = document.getElementById("email-error"); |
|||
|
|||
// Email regex |
|||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
|||
|
|||
if (!emailRegex.test(emailValue)) { |
|||
emailInput.classList.add("error"); |
|||
emailInput.classList.remove("success"); |
|||
errorElement.textContent = "Zadejte platný email"; |
|||
errorElement.style.display = "block"; |
|||
return false; |
|||
} |
|||
|
|||
emailInput.classList.remove("error"); |
|||
emailInput.classList.add("success"); |
|||
errorElement.style.display = "none"; |
|||
return true; |
|||
} |
|||
``` |
|||
|
|||
```css |
|||
/* CSS */ |
|||
.form-control { |
|||
border: 2px solid #ccc; |
|||
transition: border-color 0.3s; |
|||
} |
|||
|
|||
.form-control.error { |
|||
border-color: #dc3545; /* červená */ |
|||
} |
|||
|
|||
.form-control.success { |
|||
border-color: #28a745; /* zelená */ |
|||
} |
|||
|
|||
.error-message { |
|||
color: #dc3545; |
|||
font-size: 0.875rem; |
|||
display: none; |
|||
} |
|||
``` |
|||
|
|||
## ⚠️ Časté chyby |
|||
|
|||
❌ **addEventListener s závorkami** |
|||
```javascript |
|||
// ŠPATNĚ |
|||
input.addEventListener("input", validateName()); // volá funkci hned |
|||
|
|||
// SPRÁVNĚ |
|||
input.addEventListener("input", validateName); // předá referenci |
|||
``` |
|||
|
|||
❌ **Zapomenutý e.preventDefault()** |
|||
```javascript |
|||
form.addEventListener("submit", function(e) { |
|||
e.preventDefault(); // MUSÍ BÝT! Jinak se formulář odešle |
|||
// validace... |
|||
}); |
|||
``` |
|||
|
|||
❌ **RegEx bez escape znaků** |
|||
```javascript |
|||
// ŠPATNĚ |
|||
const regex = /^user@email.com$/; // . = jakýkoliv znak |
|||
|
|||
// SPRÁVNĚ |
|||
const regex = /^user@email\.com$/; // \. = literální tečka |
|||
``` |
|||
|
|||
## 🎓 Hodnocení (20 bodů) |
|||
|
|||
- **addEventListener použití** (4b) - všechny eventy přes addEventListener |
|||
- **Validační funkce** (6b) - 6 funkčních validací |
|||
- **RegEx implementace** (3b) - správné regex pro email, heslo, jméno |
|||
- **Visual feedback** (4b) - červená/zelená border, chybové zprávy |
|||
- **Submit handling** (3b) - kontrola všech polí, preventDefault |
|||
|
|||
## 🔗 Užitečné odkazy |
|||
|
|||
- [Form Validation - W3Schools](https://www.w3schools.com/js/js_validation.asp) |
|||
- [RegEx Tutorial - RegExr](https://regexr.com/) |
|||
- [addEventListener - MDN](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) |
|||
- [RegEx Tester - Regex101](https://regex101.com/) |
|||
|
|||
## ⏱️ Odhadovaný čas |
|||
|
|||
**90-120 minut** |
|||
|
|||
## 💪 Bonus výzvy |
|||
|
|||
1. **Password strength meter** - slabé/střední/silné heslo |
|||
2. **Show/hide password** - ikona oka pro zobrazení hesla |
|||
3. **Email suggestion** - když napíšu `@gmal.com` → návrh `@gmail.com` |
|||
4. **Character counter** - zobrazí 3/20 znaků |
|||
5. **Shake animation** - třese se při chybě |
|||
|
|||
## 🎯 Po dokončení |
|||
|
|||
Po dokončení tohoto projektu budete rozumět: |
|||
- Modernímu event handlingu (addEventListener) |
|||
- Form validation v JavaScriptu |
|||
- RegEx pro validaci formátů |
|||
- Visual feedback a UX best practices |
|||
|
|||
Bootstrap form validation vám pak bude dávat smysl, protože budete vědět, co se děje "pod kapotou"! |
|||
|
|||
➡️ **Další projekt:** AI 04 - Komplexní Bootstrap Prep Projekt |
|||
@ -0,0 +1,93 @@ |
|||
# AI 03 - Pokročilá Validace Formulářů s JavaScript |
|||
|
|||
## 🎯 Cíl projektu |
|||
Naučit se pokročilou práci s formuláři a JavaScript validací. Bootstrap má vestavěné validační třídy, takže je důležité rozumět, jak validace funguje. |
|||
|
|||
## 📝 Zadání |
|||
|
|||
Vytvořte registrační formulář s real-time validací pomocí JavaScriptu. |
|||
|
|||
### HTML požadavky - Formulářové pole: |
|||
|
|||
1. **Jméno** (text input) |
|||
- Min. 3 znaky, max. 20 znaků |
|||
- Pouze písmena |
|||
|
|||
2. **Email** (email input) |
|||
- Musí obsahovat @ a . |
|||
- Validní formát emailu |
|||
|
|||
3. **Heslo** (password input) |
|||
- Min. 8 znaků |
|||
- Alespoň 1 velké písmeno |
|||
- Alespoň 1 číslo |
|||
- Alespoň 1 speciální znak |
|||
|
|||
4. **Potvrzení hesla** (password input) |
|||
- Musí se shodovat s heslem |
|||
|
|||
5. **Věk** (number input) |
|||
- Min. 18, max. 120 |
|||
|
|||
6. **Souhlas s podmínkami** (checkbox) |
|||
- Musí být zaškrtnutý |
|||
|
|||
7. **Tlačítko Registrovat** (button) |
|||
|
|||
### JavaScript požadavky: |
|||
|
|||
#### 1. Použijte `addEventListener` místo inline onclick! |
|||
```javascript |
|||
document.getElementById("jmeno").addEventListener("input", validateName); |
|||
``` |
|||
|
|||
#### 2. Real-time validace |
|||
- Validujte při každé změně (event: "input") |
|||
- Zobrazujte chybové zprávy pod každým polem |
|||
- Měňte border color (červená = chyba, zelená = OK) |
|||
|
|||
#### 3. Validační funkce |
|||
Vytvořte separátní funkce pro validaci: |
|||
- `validateName()` |
|||
- `validateEmail()` |
|||
- `validatePassword()` |
|||
- `validatePasswordMatch()` |
|||
- `validateAge()` |
|||
- `validateCheckbox()` |
|||
|
|||
#### 4. Submit validace |
|||
- Při kliknutí na "Registrovat" zkontrolujte všechna pole |
|||
- Pokud je něco špatně, zobrazte alert a zabraňte odeslání |
|||
- Pokud je vše OK, zobrazte success zprávu |
|||
|
|||
#### 5. Visual feedback |
|||
- Červený border + chybová zpráva = chyba |
|||
- Zelený border = OK |
|||
- Ikona checkmark (✓) u správných polí |
|||
- Ikona X (✗) u chybných polí |
|||
|
|||
### CSS požadavky: |
|||
- Hezký design formuláře |
|||
- Responzivní |
|||
- Animace při chybách (shake effect) |
|||
|
|||
## 💡 Co se naučíte: |
|||
- addEventListener vs inline events |
|||
- Form validation v JavaScriptu |
|||
- RegEx (regulární výrazy) pro validaci |
|||
- DOM manipulace (classList, innerHTML) |
|||
- Event handling |
|||
- Podmínky a logické operátory |
|||
|
|||
## 🔗 Užitečné odkazy: |
|||
- Form Validation: https://www.w3schools.com/js/js_validation.asp |
|||
- RegEx Tutorial: https://regexr.com/ |
|||
- addEventListener: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener |
|||
|
|||
## ⏱️ Odhadovaný čas: 90-120 minut |
|||
|
|||
## 💪 Bonus výzvy: |
|||
1. Password strength meter (slabé/střední/silné heslo) |
|||
2. Show/hide password tlačítko |
|||
3. Email suggestion (když napíšu @gmal.com → návrd @gmail.com) |
|||
4. Character counter pro jméno |
|||
@ -0,0 +1,50 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>AI 03 - Validace Formulářů</title> |
|||
<link rel="stylesheet" href="style.css"> |
|||
</head> |
|||
<body> |
|||
<div class="container"> |
|||
<h1>Registrace</h1> |
|||
|
|||
<form id="registrationForm"> |
|||
<!-- TODO: Vytvořte formulářová pole podle zadání --> |
|||
|
|||
<!-- Příklad struktury pro jedno pole: --> |
|||
<!-- |
|||
<div class="form-group"> |
|||
<label for="jmeno">Jméno:</label> |
|||
<input type="text" id="jmeno" name="jmeno"> |
|||
<span class="error-message" id="jmenoError"></span> |
|||
</div> |
|||
--> |
|||
|
|||
<!-- 1. Pole pro jméno --> |
|||
|
|||
|
|||
<!-- 2. Pole pro email --> |
|||
|
|||
|
|||
<!-- 3. Pole pro heslo --> |
|||
|
|||
|
|||
<!-- 4. Pole pro potvrzení hesla --> |
|||
|
|||
|
|||
<!-- 5. Pole pro věk --> |
|||
|
|||
|
|||
<!-- 6. Checkbox pro souhlas s podmínkami --> |
|||
|
|||
|
|||
<!-- 7. Tlačítko --> |
|||
|
|||
</form> |
|||
</div> |
|||
|
|||
<script src="script.js"></script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,256 @@ |
|||
/* AI 03 - Validace Formulářů - ŘEŠENÍ */ |
|||
|
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
body { |
|||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|||
min-height: 100vh; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 20px; |
|||
} |
|||
|
|||
.container { |
|||
background: white; |
|||
padding: 40px; |
|||
border-radius: 10px; |
|||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); |
|||
width: 100%; |
|||
max-width: 500px; |
|||
} |
|||
|
|||
h1 { |
|||
text-align: center; |
|||
color: #333; |
|||
margin-bottom: 30px; |
|||
font-size: 2rem; |
|||
} |
|||
|
|||
/* ======================================== |
|||
FORM STYLING |
|||
======================================== */ |
|||
|
|||
.form-group { |
|||
margin-bottom: 20px; |
|||
position: relative; |
|||
} |
|||
|
|||
.form-group label { |
|||
display: block; |
|||
margin-bottom: 8px; |
|||
color: #333; |
|||
font-weight: 600; |
|||
font-size: 0.95rem; |
|||
} |
|||
|
|||
.form-group input { |
|||
width: 100%; |
|||
padding: 12px 15px; |
|||
border: 2px solid #ddd; |
|||
border-radius: 5px; |
|||
font-size: 1rem; |
|||
transition: all 0.3s ease; |
|||
font-family: inherit; |
|||
} |
|||
|
|||
.form-group input:focus { |
|||
outline: none; |
|||
border-color: #667eea; |
|||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); |
|||
} |
|||
|
|||
.form-group small { |
|||
display: block; |
|||
margin-top: 5px; |
|||
color: #999; |
|||
font-size: 0.85rem; |
|||
} |
|||
|
|||
/* ======================================== |
|||
VALIDATION STATES |
|||
======================================== */ |
|||
|
|||
/* SUCCESS - zelený border */ |
|||
.form-group.success input { |
|||
border-color: #2ecc71; |
|||
} |
|||
|
|||
/* Přidá checkmark ikonu */ |
|||
.form-group.success input { |
|||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%232ecc71' d='M7.629 14.566l-4.586-4.586-1.457 1.457 6.043 6.043 12.957-12.957-1.457-1.457z'/%3E%3C/svg%3E"); |
|||
background-repeat: no-repeat; |
|||
background-position: right 12px center; |
|||
background-size: 20px; |
|||
padding-right: 40px; |
|||
} |
|||
|
|||
/* ERROR - červený border */ |
|||
.form-group.error input { |
|||
border-color: #e74c3c; |
|||
} |
|||
|
|||
/* Přidá X ikonu */ |
|||
.form-group.error input { |
|||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23e74c3c' d='M10 8.586l-7.071-7.071-1.414 1.414 7.071 7.071-7.071 7.071 1.414 1.414 7.071-7.071 7.071 7.071 1.414-1.414-7.071-7.071 7.071-7.071-1.414-1.414z'/%3E%3C/svg%3E"); |
|||
background-repeat: no-repeat; |
|||
background-position: right 12px center; |
|||
background-size: 16px; |
|||
padding-right: 40px; |
|||
} |
|||
|
|||
/* ======================================== |
|||
ERROR MESSAGE |
|||
======================================== */ |
|||
|
|||
.error-message { |
|||
display: block; |
|||
color: #e74c3c; |
|||
font-size: 0.875rem; |
|||
margin-top: 5px; |
|||
min-height: 20px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
/* ======================================== |
|||
CHECKBOX GROUP |
|||
======================================== */ |
|||
|
|||
.checkbox-group { |
|||
margin-bottom: 25px; |
|||
} |
|||
|
|||
.checkbox-group label { |
|||
display: flex; |
|||
align-items: center; |
|||
font-weight: normal; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.checkbox-group input[type="checkbox"] { |
|||
width: auto; |
|||
margin-right: 10px; |
|||
cursor: pointer; |
|||
width: 18px; |
|||
height: 18px; |
|||
} |
|||
|
|||
/* ======================================== |
|||
SUBMIT BUTTON |
|||
======================================== */ |
|||
|
|||
.btn-submit { |
|||
width: 100%; |
|||
padding: 15px; |
|||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|||
color: white; |
|||
border: none; |
|||
border-radius: 5px; |
|||
font-size: 1.1rem; |
|||
font-weight: bold; |
|||
cursor: pointer; |
|||
transition: transform 0.3s ease, box-shadow 0.3s ease; |
|||
} |
|||
|
|||
.btn-submit:hover { |
|||
transform: translateY(-2px); |
|||
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); |
|||
} |
|||
|
|||
.btn-submit:active { |
|||
transform: translateY(0); |
|||
} |
|||
|
|||
.btn-submit:disabled { |
|||
background: #ccc; |
|||
cursor: not-allowed; |
|||
transform: none; |
|||
} |
|||
|
|||
/* ======================================== |
|||
SUCCESS MESSAGE |
|||
======================================== */ |
|||
|
|||
.success-box { |
|||
text-align: center; |
|||
padding: 30px; |
|||
background-color: #d4edda; |
|||
border: 2px solid #28a745; |
|||
border-radius: 10px; |
|||
margin-top: 20px; |
|||
} |
|||
|
|||
.success-box h2 { |
|||
color: #155724; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.success-box p { |
|||
color: #155724; |
|||
} |
|||
|
|||
/* ======================================== |
|||
ANIMATIONS |
|||
======================================== */ |
|||
|
|||
/* Shake animace pro chyby */ |
|||
@keyframes shake { |
|||
0%, 100% { |
|||
transform: translateX(0); |
|||
} |
|||
10%, 30%, 50%, 70%, 90% { |
|||
transform: translateX(-10px); |
|||
} |
|||
20%, 40%, 60%, 80% { |
|||
transform: translateX(10px); |
|||
} |
|||
} |
|||
|
|||
.form-group.error { |
|||
animation: shake 0.5s ease; |
|||
} |
|||
|
|||
/* Fade in animace */ |
|||
@keyframes fadeIn { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(-20px); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
.success-box { |
|||
animation: fadeIn 0.5s ease; |
|||
} |
|||
|
|||
/* ======================================== |
|||
RESPONSIVE |
|||
======================================== */ |
|||
|
|||
@media screen and (max-width: 480px) { |
|||
.container { |
|||
padding: 25px; |
|||
} |
|||
|
|||
h1 { |
|||
font-size: 1.5rem; |
|||
} |
|||
|
|||
.form-group input { |
|||
padding: 10px 12px; |
|||
font-size: 0.95rem; |
|||
} |
|||
|
|||
.btn-submit { |
|||
padding: 12px; |
|||
font-size: 1rem; |
|||
} |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>AI 03 - Validace Formulářů - ŘEŠENÍ</title> |
|||
<link rel="stylesheet" href="reseni.css"> |
|||
</head> |
|||
<body> |
|||
<div class="container"> |
|||
<h1>Registrace</h1> |
|||
|
|||
<form id="registrationForm"> |
|||
<!-- Jméno --> |
|||
<div class="form-group"> |
|||
<label for="jmeno">Jméno:</label> |
|||
<input type="text" id="jmeno" name="jmeno" placeholder="Jan Novák"> |
|||
<span class="error-message" id="jmenoError"></span> |
|||
<small>Min. 3 znaky, max. 20 znaků, pouze písmena</small> |
|||
</div> |
|||
|
|||
<!-- Email --> |
|||
<div class="form-group"> |
|||
<label for="email">Email:</label> |
|||
<input type="email" id="email" name="email" placeholder="jan@email.cz"> |
|||
<span class="error-message" id="emailError"></span> |
|||
<small>Zadejte platný email</small> |
|||
</div> |
|||
|
|||
<!-- Heslo --> |
|||
<div class="form-group"> |
|||
<label for="heslo">Heslo:</label> |
|||
<input type="password" id="heslo" name="heslo" placeholder="••••••••"> |
|||
<span class="error-message" id="hesloError"></span> |
|||
<small>Min. 8 znaků, 1 velké písmeno, 1 číslo, 1 speciální znak</small> |
|||
</div> |
|||
|
|||
<!-- Potvrzení hesla --> |
|||
<div class="form-group"> |
|||
<label for="hesloPotvrzeni">Potvrzení hesla:</label> |
|||
<input type="password" id="hesloPotvrzeni" name="hesloPotvrzeni" placeholder="••••••••"> |
|||
<span class="error-message" id="hesloPotvrzeniError"></span> |
|||
<small>Hesla se musí shodovat</small> |
|||
</div> |
|||
|
|||
<!-- Věk --> |
|||
<div class="form-group"> |
|||
<label for="vek">Věk:</label> |
|||
<input type="number" id="vek" name="vek" placeholder="18"> |
|||
<span class="error-message" id="vekError"></span> |
|||
<small>Min. 18 let</small> |
|||
</div> |
|||
|
|||
<!-- Checkbox --> |
|||
<div class="form-group checkbox-group"> |
|||
<label> |
|||
<input type="checkbox" id="souhlas" name="souhlas"> |
|||
Souhlasím s podmínkami používání |
|||
</label> |
|||
<span class="error-message" id="souhlasError"></span> |
|||
</div> |
|||
|
|||
<!-- Submit button --> |
|||
<button type="submit" class="btn-submit">Registrovat</button> |
|||
</form> |
|||
|
|||
<!-- Success message (skrytá) --> |
|||
<div id="successMessage" class="success-box" style="display: none;"> |
|||
<h2>✓ Registrace úspěšná!</h2> |
|||
<p>Váš účet byl úspěšně vytvořen.</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<script src="reseni.js"></script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,376 @@ |
|||
// AI 03 - Validace Formulářů - ŘEŠENÍ
|
|||
|
|||
console.log("Script načten"); |
|||
|
|||
// ========================================
|
|||
// ZÍSKÁNÍ REFERENCÍ NA ELEMENTY
|
|||
// ========================================
|
|||
|
|||
const jmenoInput = document.getElementById("jmeno"); |
|||
const emailInput = document.getElementById("email"); |
|||
const hesloInput = document.getElementById("heslo"); |
|||
const hesloPotvrzeniInput = document.getElementById("hesloPotvrzeni"); |
|||
const vekInput = document.getElementById("vek"); |
|||
const souhlasInput = document.getElementById("souhlas"); |
|||
const form = document.getElementById("registrationForm"); |
|||
const successMessage = document.getElementById("successMessage"); |
|||
|
|||
// ========================================
|
|||
// EVENT LISTENERS - REAL-TIME VALIDACE
|
|||
// ========================================
|
|||
|
|||
// Důležité: Používáme addEventListener místo inline onclick!
|
|||
// Výhody:
|
|||
// 1. Oddělení HTML a JavaScriptu
|
|||
// 2. Můžeme přidat více listenerů na jeden element
|
|||
// 3. Lepší kontrola nad event objektem
|
|||
|
|||
jmenoInput.addEventListener("input", validateName); |
|||
emailInput.addEventListener("input", validateEmail); |
|||
hesloInput.addEventListener("input", validatePassword); |
|||
hesloPotvrzeniInput.addEventListener("input", validatePasswordMatch); |
|||
vekInput.addEventListener("input", validateAge); |
|||
souhlasInput.addEventListener("change", validateCheckbox); |
|||
|
|||
// Event listener pro submit formuláře
|
|||
form.addEventListener("submit", handleSubmit); |
|||
|
|||
// ========================================
|
|||
// VALIDAČNÍ FUNKCE
|
|||
// ========================================
|
|||
|
|||
/** |
|||
* Validace jména |
|||
* Požadavky: |
|||
* - Min. 3 znaky |
|||
* - Max. 20 znaků |
|||
* - Pouze písmena (včetně diakritiky) |
|||
*/ |
|||
function validateName() { |
|||
const jmeno = jmenoInput.value.trim(); |
|||
|
|||
// Kontrola prázdného pole
|
|||
if (jmeno === "") { |
|||
showError(jmenoInput, "Jméno je povinné"); |
|||
return false; |
|||
} |
|||
|
|||
// Kontrola délky
|
|||
if (jmeno.length < 3) { |
|||
showError(jmenoInput, "Jméno musí mít alespoň 3 znaky"); |
|||
return false; |
|||
} |
|||
|
|||
if (jmeno.length > 20) { |
|||
showError(jmenoInput, "Jméno může mít maximálně 20 znaků"); |
|||
return false; |
|||
} |
|||
|
|||
// RegEx pro kontrolu, že obsahuje pouze písmena (včetně české diakritiky)
|
|||
// ^ = začátek stringu
|
|||
// [a-zA-Z...] = povolené znaky
|
|||
// \s = mezera (povolíme mezery mezi jménem a příjmením)
|
|||
// + = jeden nebo více
|
|||
// $ = konec stringu
|
|||
const nameRegex = /^[a-zA-ZáčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ\s]+$/; |
|||
|
|||
if (!nameRegex.test(jmeno)) { |
|||
showError(jmenoInput, "Jméno může obsahovat pouze písmena"); |
|||
return false; |
|||
} |
|||
|
|||
// Vše OK!
|
|||
showSuccess(jmenoInput); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Validace emailu |
|||
* Požadavek: Validní formát emailu (obsahuje @ a .) |
|||
*/ |
|||
function validateEmail() { |
|||
const email = emailInput.value.trim(); |
|||
|
|||
if (email === "") { |
|||
showError(emailInput, "Email je povinný"); |
|||
return false; |
|||
} |
|||
|
|||
// RegEx pro email validaci
|
|||
// [^\s@]+ = jeden nebo více znaků, které nejsou mezera nebo @
|
|||
// @ = musí obsahovat @
|
|||
// [^\s@]+ = doména
|
|||
// \. = musí obsahovat tečku
|
|||
// [^\s@]+ = koncovka (.cz, .com, atd.)
|
|||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
|||
|
|||
if (!emailRegex.test(email)) { |
|||
showError(emailInput, "Zadejte platný email"); |
|||
return false; |
|||
} |
|||
|
|||
showSuccess(emailInput); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Validace hesla |
|||
* Požadavky: |
|||
* - Min. 8 znaků |
|||
* - Alespoň 1 velké písmeno |
|||
* - Alespoň 1 číslo |
|||
* - Alespoň 1 speciální znak |
|||
*/ |
|||
function validatePassword() { |
|||
const heslo = hesloInput.value; |
|||
|
|||
if (heslo === "") { |
|||
showError(hesloInput, "Heslo je povinné"); |
|||
return false; |
|||
} |
|||
|
|||
// Kontrola délky
|
|||
if (heslo.length < 8) { |
|||
showError(hesloInput, "Heslo musí mít alespoň 8 znaků"); |
|||
return false; |
|||
} |
|||
|
|||
// Kontrola velkého písmena
|
|||
// [A-Z] = obsahuje alespoň jedno velké písmeno
|
|||
if (!/[A-Z]/.test(heslo)) { |
|||
showError(hesloInput, "Heslo musí obsahovat alespoň jedno velké písmeno"); |
|||
return false; |
|||
} |
|||
|
|||
// Kontrola čísla
|
|||
// [0-9] = obsahuje alespoň jedno číslo
|
|||
if (!/[0-9]/.test(heslo)) { |
|||
showError(hesloInput, "Heslo musí obsahovat alespoň jedno číslo"); |
|||
return false; |
|||
} |
|||
|
|||
// Kontrola speciálního znaku
|
|||
// [!@#$%^&*] = obsahuje alespoň jeden speciální znak
|
|||
if (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(heslo)) { |
|||
showError(hesloInput, "Heslo musí obsahovat alespoň jeden speciální znak"); |
|||
return false; |
|||
} |
|||
|
|||
showSuccess(hesloInput); |
|||
|
|||
// Pokud je heslo validní, zkontroluj i potvrzení hesla
|
|||
if (hesloPotvrzeniInput.value !== "") { |
|||
validatePasswordMatch(); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Validace shody hesel |
|||
*/ |
|||
function validatePasswordMatch() { |
|||
const heslo = hesloInput.value; |
|||
const hesloPotvrzeni = hesloPotvrzeniInput.value; |
|||
|
|||
if (hesloPotvrzeni === "") { |
|||
showError(hesloPotvrzeniInput, "Potvrzení hesla je povinné"); |
|||
return false; |
|||
} |
|||
|
|||
// Porovnání hesel
|
|||
if (heslo !== hesloPotvrzeni) { |
|||
showError(hesloPotvrzeniInput, "Hesla se neshodují"); |
|||
return false; |
|||
} |
|||
|
|||
showSuccess(hesloPotvrzeniInput); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Validace věku |
|||
* Požadavek: Min. 18 let, max. 120 let |
|||
*/ |
|||
function validateAge() { |
|||
const vek = parseInt(vekInput.value); |
|||
|
|||
if (isNaN(vek) || vekInput.value === "") { |
|||
showError(vekInput, "Věk je povinný"); |
|||
return false; |
|||
} |
|||
|
|||
if (vek < 18) { |
|||
showError(vekInput, "Musíte být starší 18 let"); |
|||
return false; |
|||
} |
|||
|
|||
if (vek > 120) { |
|||
showError(vekInput, "Zadejte reálný věk"); |
|||
return false; |
|||
} |
|||
|
|||
showSuccess(vekInput); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* Validace checkboxu |
|||
* Požadavek: Musí být zaškrtnutý |
|||
*/ |
|||
function validateCheckbox() { |
|||
// .checked vrací true/false podle toho, jestli je checkbox zaškrtnutý
|
|||
if (!souhlasInput.checked) { |
|||
showError(souhlasInput, "Musíte souhlasit s podmínkami"); |
|||
return false; |
|||
} |
|||
|
|||
showSuccess(souhlasInput); |
|||
return true; |
|||
} |
|||
|
|||
// ========================================
|
|||
// HELPER FUNKCE
|
|||
// ========================================
|
|||
|
|||
/** |
|||
* Zobrazí chybovou zprávu a nastaví error stav |
|||
* @param {HTMLElement} inputElement - Input element |
|||
* @param {string} message - Chybová zpráva |
|||
*/ |
|||
function showError(inputElement, message) { |
|||
// Najdi parent element (.form-group)
|
|||
// .parentElement vrací rodičovský element
|
|||
const formGroup = inputElement.parentElement; |
|||
|
|||
// Přidej třídu "error" pro styling
|
|||
formGroup.classList.add("error"); |
|||
|
|||
// Odeber třídu "success" (pokud tam byla)
|
|||
formGroup.classList.remove("success"); |
|||
|
|||
// Najdi element pro chybovou zprávu
|
|||
// Předpokládáme, že má id ve formátu: inputId + "Error"
|
|||
const errorElement = formGroup.querySelector(".error-message"); |
|||
|
|||
// Nastav text chybové zprávy
|
|||
if (errorElement) { |
|||
errorElement.textContent = message; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Zobrazí success stav (zelený border, checkmark) |
|||
* @param {HTMLElement} inputElement - Input element |
|||
*/ |
|||
function showSuccess(inputElement) { |
|||
const formGroup = inputElement.parentElement; |
|||
|
|||
// Přidej třídu "success"
|
|||
formGroup.classList.add("success"); |
|||
|
|||
// Odeber třídu "error"
|
|||
formGroup.classList.remove("error"); |
|||
|
|||
// Vyčisti chybovou zprávu
|
|||
const errorElement = formGroup.querySelector(".error-message"); |
|||
if (errorElement) { |
|||
errorElement.textContent = ""; |
|||
} |
|||
} |
|||
|
|||
// ========================================
|
|||
// SUBMIT HANDLER
|
|||
// ========================================
|
|||
|
|||
/** |
|||
* Handler pro submit formuláře |
|||
* @param {Event} e - Event objekt |
|||
*/ |
|||
function handleSubmit(e) { |
|||
// Zabraň výchozímu chování (odeslání formuláře a reload stránky)
|
|||
e.preventDefault(); |
|||
|
|||
console.log("Formulář odeslán"); |
|||
|
|||
// Zavolej všechny validační funkce
|
|||
const isNameValid = validateName(); |
|||
const isEmailValid = validateEmail(); |
|||
const isPasswordValid = validatePassword(); |
|||
const isPasswordMatchValid = validatePasswordMatch(); |
|||
const isAgeValid = validateAge(); |
|||
const isCheckboxValid = validateCheckbox(); |
|||
|
|||
// Zkontroluj, jestli jsou všechna pole validní
|
|||
// Logický AND (&&) - vrací true pouze pokud jsou všechny hodnoty true
|
|||
const isFormValid = |
|||
isNameValid && |
|||
isEmailValid && |
|||
isPasswordValid && |
|||
isPasswordMatchValid && |
|||
isAgeValid && |
|||
isCheckboxValid; |
|||
|
|||
if (isFormValid) { |
|||
// Vše OK - zobraz success zprávu
|
|||
console.log("✓ Formulář je validní!"); |
|||
|
|||
// Schovat formulář
|
|||
form.style.display = "none"; |
|||
|
|||
// Zobrazit success zprávu
|
|||
successMessage.style.display = "block"; |
|||
|
|||
// V reálné aplikaci bychom zde odeslali data na server:
|
|||
// fetch("/api/register", {
|
|||
// method: "POST",
|
|||
// body: JSON.stringify({
|
|||
// jmeno: jmenoInput.value,
|
|||
// email: emailInput.value,
|
|||
// ...
|
|||
// })
|
|||
// });
|
|||
|
|||
} else { |
|||
// Něco je špatně - zobraz alert
|
|||
console.log("✗ Formulář obsahuje chyby!"); |
|||
alert("Prosím opravte chyby ve formuláři"); |
|||
} |
|||
} |
|||
|
|||
// ========================================
|
|||
// BONUS FUNKCE
|
|||
// ========================================
|
|||
|
|||
/** |
|||
* BONUS: Password strength meter |
|||
* Můžete přidat indikátor síly hesla |
|||
*/ |
|||
function checkPasswordStrength(password) { |
|||
let strength = 0; |
|||
|
|||
if (password.length >= 8) strength++; |
|||
if (password.length >= 12) strength++; |
|||
if (/[a-z]/.test(password)) strength++; |
|||
if (/[A-Z]/.test(password)) strength++; |
|||
if (/[0-9]/.test(password)) strength++; |
|||
if (/[^a-zA-Z0-9]/.test(password)) strength++; |
|||
|
|||
if (strength <= 2) return "Slabé"; |
|||
if (strength <= 4) return "Střední"; |
|||
return "Silné"; |
|||
} |
|||
|
|||
// ========================================
|
|||
// DEBUG INFO
|
|||
// ========================================
|
|||
|
|||
console.log("Validační skrip připraven"); |
|||
console.log("Event listenery přidány na:", { |
|||
jmeno: jmenoInput, |
|||
email: emailInput, |
|||
heslo: hesloInput, |
|||
hesloPotvrzeni: hesloPotvrzeniInput, |
|||
vek: vekInput, |
|||
souhlas: souhlasInput |
|||
}); |
|||
@ -0,0 +1,96 @@ |
|||
// AI 03 - Validace Formulářů - JavaScript
|
|||
|
|||
console.log("Script načten"); |
|||
|
|||
// TODO: Získejte reference na elementy
|
|||
// const jmenoInput = document.getElementById("jmeno");
|
|||
// const emailInput = document.getElementById("email");
|
|||
// ... atd
|
|||
|
|||
|
|||
// TODO: Přidejte event listenery pro real-time validaci
|
|||
// jmenoInput.addEventListener("input", validateName);
|
|||
// emailInput.addEventListener("input", validateEmail);
|
|||
// ... atd
|
|||
|
|||
|
|||
// TODO: Event listener pro submit formuláře
|
|||
// document.getElementById("registrationForm").addEventListener("submit", handleSubmit);
|
|||
|
|||
|
|||
// ========================================
|
|||
// VALIDAČNÍ FUNKCE
|
|||
// ========================================
|
|||
|
|||
// TODO: Funkce pro validaci jména
|
|||
function validateName() { |
|||
// 1. Získej hodnotu z inputu
|
|||
// 2. Zkontroluj délku (min 3, max 20)
|
|||
// 3. Zkontroluj, že obsahuje jen písmena (použij RegEx: /^[a-zA-ZáčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ\s]+$/)
|
|||
// 4. Zobraz chybu nebo success
|
|||
} |
|||
|
|||
// TODO: Funkce pro validaci emailu
|
|||
function validateEmail() { |
|||
// 1. Získej hodnotu
|
|||
// 2. Zkontroluj formát emailu (RegEx: /^[^\s@]+@[^\s@]+\.[^\s@]+$/)
|
|||
// 3. Zobraz výsledek
|
|||
} |
|||
|
|||
// TODO: Funkce pro validaci hesla
|
|||
function validatePassword() { |
|||
// Musí obsahovat:
|
|||
// - Min. 8 znaků
|
|||
// - Alespoň 1 velké písmeno (RegEx: /[A-Z]/)
|
|||
// - Alespoň 1 číslo (RegEx: /[0-9]/)
|
|||
// - Alespoň 1 speciální znak (RegEx: /[!@#$%^&*]/)
|
|||
} |
|||
|
|||
// TODO: Funkce pro kontrolu shody hesel
|
|||
function validatePasswordMatch() { |
|||
// Porovnej hodnoty hesla a potvrzení hesla
|
|||
} |
|||
|
|||
// TODO: Funkce pro validaci věku
|
|||
function validateAge() { |
|||
// Zkontroluj, že věk je číslo mezi 18 a 120
|
|||
} |
|||
|
|||
// TODO: Funkce pro validaci checkboxu
|
|||
function validateCheckbox() { |
|||
// Zkontroluj, že checkbox je zaškrtnutý (.checked)
|
|||
} |
|||
|
|||
// ========================================
|
|||
// HELPER FUNKCE
|
|||
// ========================================
|
|||
|
|||
// TODO: Funkce pro zobrazení chyby
|
|||
function showError(inputElement, message) { |
|||
// 1. Najdi parent element (.form-group)
|
|||
// 2. Přidej třídu "error"
|
|||
// 3. Odeber třídu "success"
|
|||
// 4. Najdi .error-message a nastav text
|
|||
// 5. Přidej shake animaci
|
|||
} |
|||
|
|||
// TODO: Funkce pro zobrazení success
|
|||
function showSuccess(inputElement) { |
|||
// 1. Najdi parent element
|
|||
// 2. Přidej třídu "success"
|
|||
// 3. Odeber třídu "error"
|
|||
// 4. Vyčisti error message
|
|||
} |
|||
|
|||
// ========================================
|
|||
// SUBMIT HANDLER
|
|||
// ========================================
|
|||
|
|||
function handleSubmit(e) { |
|||
e.preventDefault(); // Zabraň odeslání formuláře
|
|||
|
|||
// TODO: Zavolej všechny validační funkce
|
|||
// TODO: Zkontroluj, jestli jsou všechna pole validní
|
|||
// TODO: Pokud ano, zobraz success zprávu
|
|||
// TODO: Pokud ne, zobraz alert s chybou
|
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
/* AI 03 - Validace Formulářů */ |
|||
|
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
body { |
|||
font-family: Arial, Helvetica, sans-serif; |
|||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|||
min-height: 100vh; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding: 20px; |
|||
} |
|||
|
|||
.container { |
|||
background: white; |
|||
padding: 40px; |
|||
border-radius: 10px; |
|||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); |
|||
width: 100%; |
|||
max-width: 500px; |
|||
} |
|||
|
|||
h1 { |
|||
text-align: center; |
|||
color: #333; |
|||
margin-bottom: 30px; |
|||
} |
|||
|
|||
/* TODO: Nastylujte .form-group */ |
|||
|
|||
|
|||
/* TODO: Nastylujte label */ |
|||
|
|||
|
|||
/* TODO: Nastylujte input */ |
|||
|
|||
|
|||
/* TODO: Přidejte třídy pro validaci */ |
|||
/* .form-group.success input - zelený border */ |
|||
|
|||
|
|||
/* .form-group.error input - červený border */ |
|||
|
|||
|
|||
/* TODO: Nastylujte .error-message */ |
|||
|
|||
|
|||
/* TODO: Nastylujte button */ |
|||
|
|||
|
|||
/* TODO: Přidejte shake animaci pro chyby */ |
|||
@keyframes shake { |
|||
/* Vytvořte shake efekt pomocí translateX */ |
|||
} |
|||
@ -0,0 +1,377 @@ |
|||
# AI 04 - Komplexní Bootstrap Prep Projekt |
|||
|
|||
## 🎯 Cíl projektu |
|||
|
|||
**Finální komplexní projekt** kombinující **VŠECHNY naučené koncepty**. Po dokončení tohoto projektu budete plně připraveni na Bootstrap a budete rozumět, proč a jak framework funguje! |
|||
|
|||
## 📋 Co tento projekt procvičuje |
|||
|
|||
### HTML: |
|||
✅ Sémantické elementy (nav, main, section, article, aside, footer) |
|||
✅ Formuláře |
|||
✅ Strukturu moderní webové stránky |
|||
|
|||
### CSS: |
|||
✅ **Grid & Flexbox** - komplexní layouty |
|||
✅ **Positioning** - všechny typy (fixed, sticky, relative, absolute) |
|||
✅ **Media queries** - plná responzivita |
|||
✅ **CSS proměnné** - custom properties |
|||
✅ **Moderní jednotky** - rem, em, vh, vw |
|||
✅ **Gradienty, shadows, transitions** |
|||
✅ **Animations** - fadeIn, slideIn |
|||
✅ **Pokročilé selektory** - nth-child, ::before, ::after |
|||
|
|||
### JavaScript: |
|||
✅ **addEventListener** |
|||
✅ **DOM manipulace** |
|||
✅ **Form validation** |
|||
✅ **Event handling** |
|||
✅ **Scroll efekty** |
|||
✅ **Modals, accordions, toggles** |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- **ZADANI.md** - kompletní zadání projektu |
|||
- **index.html** - startovací HTML (s TODO komentáři) |
|||
- **css/style.css** - hlavní CSS (s TODO komentáři) |
|||
- **css/animations.css** - CSS animace |
|||
- **js/main.js** - hlavní JavaScript |
|||
- **js/validation.js** - form validace |
|||
- **js/scroll.js** - scroll efekty |
|||
- **reseni/** - kompletní řešení se všemi soubory |
|||
|
|||
## 🚀 Co budete vytvářet |
|||
|
|||
**Responzivní Landing Page** pro fiktivní produkt (fitness app, e-learning, SaaS, atd.) |
|||
|
|||
### Struktura stránky: |
|||
|
|||
``` |
|||
┌─────────────────────────────────────┐ |
|||
│ FIXNÍ NAVIGACE (position: fixed) │ |
|||
├─────────────────────────────────────┤ |
|||
│ │ |
|||
│ HERO SEKCE (header) │ |
|||
│ Call-to-Action tlačítko │ |
|||
│ │ |
|||
├──────────────┬──────────────────────┤ |
|||
│ STICKY │ │ |
|||
│ ASIDE │ FEATURES (grid) │ |
|||
│ (boční) │ │ |
|||
│ │ PRICING CARDS │ |
|||
│ │ (grid) │ |
|||
│ │ │ |
|||
│ │ TESTIMONIALS │ |
|||
│ │ (flex) │ |
|||
│ │ │ |
|||
│ │ CONTACT FORM │ |
|||
│ │ (validation) │ |
|||
├──────────────┴──────────────────────┤ |
|||
│ FOOTER │ |
|||
└─────────────────────────────────────┘ |
|||
``` |
|||
|
|||
## 💡 Klíčové techniky |
|||
|
|||
### 1. CSS Grid Layout |
|||
|
|||
**Features sekce:** |
|||
```css |
|||
.features { |
|||
display: grid; |
|||
grid-template-columns: repeat(3, 1fr); /* 3 sloupce */ |
|||
gap: 2rem; |
|||
} |
|||
|
|||
@media (max-width: 768px) { |
|||
.features { |
|||
grid-template-columns: repeat(2, 1fr); /* 2 na tabletu */ |
|||
} |
|||
} |
|||
|
|||
@media (max-width: 480px) { |
|||
.features { |
|||
grid-template-columns: 1fr; /* 1 na mobilu */ |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### 2. CSS Proměnné (Custom Properties) |
|||
|
|||
```css |
|||
:root { |
|||
--primary-color: #667eea; |
|||
--secondary-color: #764ba2; |
|||
--text-color: #333; |
|||
--bg-color: #f8f9fa; |
|||
--spacing-unit: 1rem; |
|||
--border-radius: 8px; |
|||
} |
|||
|
|||
.button { |
|||
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); |
|||
padding: calc(var(--spacing-unit) * 0.75) calc(var(--spacing-unit) * 1.5); |
|||
border-radius: var(--border-radius); |
|||
} |
|||
``` |
|||
|
|||
### 3. Pricing Toggle (JavaScript) |
|||
|
|||
```javascript |
|||
const toggle = document.getElementById("pricing-toggle"); |
|||
const monthlyPrices = document.querySelectorAll(".monthly-price"); |
|||
const yearlyPrices = document.querySelectorAll(".yearly-price"); |
|||
|
|||
toggle.addEventListener("change", function() { |
|||
if (this.checked) { |
|||
// Zobraz roční ceny |
|||
monthlyPrices.forEach(el => el.style.display = "none"); |
|||
yearlyPrices.forEach(el => el.style.display = "block"); |
|||
} else { |
|||
// Zobraz měsíční ceny |
|||
monthlyPrices.forEach(el => el.style.display = "block"); |
|||
yearlyPrices.forEach(el => el.style.display = "none"); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
### 4. Smooth Scroll k sekcím |
|||
|
|||
```javascript |
|||
document.querySelectorAll('a[href^="#"]').forEach(anchor => { |
|||
anchor.addEventListener("click", function(e) { |
|||
e.preventDefault(); |
|||
const target = document.querySelector(this.getAttribute("href")); |
|||
target.scrollIntoView({ |
|||
behavior: "smooth", |
|||
block: "start" |
|||
}); |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
### 5. Scroll to Top tlačítko |
|||
|
|||
```javascript |
|||
const scrollTopBtn = document.getElementById("scroll-top"); |
|||
|
|||
window.addEventListener("scroll", function() { |
|||
if (window.pageYOffset > 300) { |
|||
scrollTopBtn.classList.add("show"); |
|||
} else { |
|||
scrollTopBtn.classList.remove("show"); |
|||
} |
|||
}); |
|||
|
|||
scrollTopBtn.addEventListener("click", function() { |
|||
window.scrollTo({ |
|||
top: 0, |
|||
behavior: "smooth" |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
### 6. Modal okno |
|||
|
|||
```javascript |
|||
const modal = document.getElementById("myModal"); |
|||
const openBtn = document.getElementById("openModal"); |
|||
const closeBtn = document.querySelector(".close"); |
|||
|
|||
openBtn.addEventListener("click", function() { |
|||
modal.style.display = "block"; |
|||
document.body.style.overflow = "hidden"; // zakáže scrollování |
|||
}); |
|||
|
|||
closeBtn.addEventListener("click", function() { |
|||
modal.style.display = "none"; |
|||
document.body.style.overflow = "auto"; |
|||
}); |
|||
|
|||
// Zavření kliknutím mimo modal |
|||
window.addEventListener("click", function(e) { |
|||
if (e.target === modal) { |
|||
modal.style.display = "none"; |
|||
document.body.style.overflow = "auto"; |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
### 7. FAQ Accordion |
|||
|
|||
```javascript |
|||
const accordionHeaders = document.querySelectorAll(".accordion-header"); |
|||
|
|||
accordionHeaders.forEach(header => { |
|||
header.addEventListener("click", function() { |
|||
const content = this.nextElementSibling; |
|||
const isActive = this.classList.contains("active"); |
|||
|
|||
// Zavři všechny ostatní |
|||
accordionHeaders.forEach(h => { |
|||
h.classList.remove("active"); |
|||
h.nextElementSibling.style.maxHeight = null; |
|||
}); |
|||
|
|||
// Toggle aktuální |
|||
if (!isActive) { |
|||
this.classList.add("active"); |
|||
content.style.maxHeight = content.scrollHeight + "px"; |
|||
} |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
### 8. Změna barvy navigace při scrollování |
|||
|
|||
```javascript |
|||
const navbar = document.querySelector("nav"); |
|||
|
|||
window.addEventListener("scroll", function() { |
|||
if (window.pageYOffset > 100) { |
|||
navbar.classList.add("scrolled"); |
|||
} else { |
|||
navbar.classList.remove("scrolled"); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
```css |
|||
nav { |
|||
background-color: transparent; |
|||
transition: background-color 0.3s ease; |
|||
} |
|||
|
|||
nav.scrolled { |
|||
background-color: rgba(255, 255, 255, 0.95); |
|||
box-shadow: 0 2px 10px rgba(0,0,0,0.1); |
|||
} |
|||
``` |
|||
|
|||
## 🎨 CSS Animations |
|||
|
|||
```css |
|||
/* Fade In */ |
|||
@keyframes fadeIn { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(20px); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
.fade-in { |
|||
animation: fadeIn 0.6s ease-out; |
|||
} |
|||
|
|||
/* Slide In */ |
|||
@keyframes slideIn { |
|||
from { |
|||
transform: translateX(-100%); |
|||
} |
|||
to { |
|||
transform: translateX(0); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## ⚠️ Časté chyby a řešení |
|||
|
|||
❌ **Fixed navigace překrývá obsah** |
|||
```css |
|||
body { |
|||
padding-top: 80px; /* výška navigace */ |
|||
} |
|||
``` |
|||
|
|||
❌ **Smooth scroll nefunguje** |
|||
```css |
|||
html { |
|||
scroll-behavior: smooth; /* CSS alternativa */ |
|||
} |
|||
``` |
|||
|
|||
❌ **Modal scrolluje pozadí** |
|||
```javascript |
|||
// Při otevření modalu |
|||
document.body.style.overflow = "hidden"; |
|||
|
|||
// Při zavření |
|||
document.body.style.overflow = "auto"; |
|||
``` |
|||
|
|||
## 🎓 Hodnocení (30 bodů) |
|||
|
|||
- **HTML struktura** (5b) - sémantické elementy, správná struktura |
|||
- **CSS Grid & Flexbox** (6b) - grid pro features/pricing, flex pro navigaci |
|||
- **Positioning** (4b) - fixed nav, sticky aside, absolute badge |
|||
- **JavaScript interaktivita** (6b) - validace, scroll, modal, accordion |
|||
- **Responzivita** (4b) - funguje na mobilu, tabletu, desktopu |
|||
- **Design & UX** (3b) - hezký design, dobré barvy, transitions |
|||
- **Clean code** (2b) - čitelný, okomentovaný kód |
|||
|
|||
## 🔗 Design inspirace |
|||
|
|||
- [Awwwards](https://www.awwwards.com/) |
|||
- [Dribbble](https://dribbble.com/) |
|||
- [Land-book](https://land-book.com/) |
|||
|
|||
## ⏱️ Odhadovaný čas |
|||
|
|||
**4-6 hodin** (pracujte postupně, ne vše najednou!) |
|||
|
|||
## 💪 Bonus úkoly (nepovinné) |
|||
|
|||
1. **Counter animace** - číselné statistiky se animují od 0 |
|||
2. **Lazy loading obrázků** - obrázky se načtou až při scrollování |
|||
3. **Dark mode toggle** - přepínač světlý/tmavý režim |
|||
4. **Carousel/Slider** - pro testimonials (bez knihoven!) |
|||
5. **Newsletter signup** - s fake AJAX requestem |
|||
6. **AOS (Animate On Scroll)** - prvky plynule přijíždějí při scrollování |
|||
|
|||
## 🎯 Po dokončení projektu |
|||
|
|||
### Co budete rozumět při učení Bootstrapu: |
|||
|
|||
✅ **Grid systém** - víte, jak funguje pod kapotou |
|||
✅ **Utility třídy** - `.m-2`, `.p-3` → víte, co dělají |
|||
✅ **Komponenty** - modals, accordions → umíte je vytvořit sami |
|||
✅ **JavaScript plugins** - rozumíte, jak fungují |
|||
✅ **Responzivita** - mobile-first přístup dává smysl |
|||
|
|||
### Bootstrap vám ušetří čas: |
|||
|
|||
```html |
|||
<!-- VÁŠE ŘEŠENÍ (40 řádků CSS) --> |
|||
<div class="pricing-card"> |
|||
<h3>Basic</h3> |
|||
<p class="price">$9/mo</p> |
|||
<button class="btn">Subscribe</button> |
|||
</div> |
|||
|
|||
<!-- BOOTSTRAP (využívá hotové třídy) --> |
|||
<div class="card text-center"> |
|||
<div class="card-body"> |
|||
<h3 class="card-title">Basic</h3> |
|||
<p class="display-4">$9/mo</p> |
|||
<button class="btn btn-primary">Subscribe</button> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
**Ale díky tomuto projektu víte, co se děje pod kapotou!** 🎉 |
|||
|
|||
## 🏆 Gratulace! |
|||
|
|||
Po dokončení všech AI projektů (01-04) jste připraveni na Bootstrap! |
|||
|
|||
Jste schopni: |
|||
- ✅ Vytvořit kompletní responzivní web bez frameworku |
|||
- ✅ Rozumět, jak frameworky fungují interně |
|||
- ✅ Přizpůsobit Bootstrap vlastním potřebám |
|||
- ✅ Debugovat problémy v Bootstrapu |
|||
|
|||
➡️ **Další krok:** Lekce 13 - Úvod do Bootstrapu |
|||
@ -0,0 +1,173 @@ |
|||
# Příklad řešení - AI 04 |
|||
|
|||
Toto je **zjednodušený příklad** řešení. Vaše implementace by měla být completnější! |
|||
|
|||
## Struktura HTML (příklad hero sekce) |
|||
|
|||
```html |
|||
<header id="hero"> |
|||
<div class="hero-content"> |
|||
<h1 class="hero-title">FitPro</h1> |
|||
<p class="hero-subtitle">Vaše cesta k lepší kondici začíná zde</p> |
|||
<a href="#contact" class="btn btn-primary">Začít zdarma</a> |
|||
</div> |
|||
</header> |
|||
``` |
|||
|
|||
## CSS Grid příklad (features) |
|||
|
|||
```css |
|||
.features-grid { |
|||
display: grid; |
|||
grid-template-columns: 1fr; /* Mobil - 1 sloupec */ |
|||
gap: 2rem; |
|||
padding: 4rem 2rem; |
|||
} |
|||
|
|||
@media (min-width: 768px) { |
|||
.features-grid { |
|||
grid-template-columns: repeat(2, 1fr); /* Tablet - 2 sloupce */ |
|||
} |
|||
} |
|||
|
|||
@media (min-width: 1024px) { |
|||
.features-grid { |
|||
grid-template-columns: repeat(3, 1fr); /* Desktop - 3 sloupce */ |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## JavaScript smooth scroll příklad |
|||
|
|||
```javascript |
|||
document.querySelectorAll('a[href^="#"]').forEach(anchor => { |
|||
anchor.addEventListener('click', function (e) { |
|||
e.preventDefault(); |
|||
const target = document.querySelector(this.getAttribute('href')); |
|||
target.scrollIntoView({ |
|||
behavior: 'smooth', |
|||
block: 'start' |
|||
}); |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
## Positioning příklad (badge) |
|||
|
|||
```css |
|||
.pricing-card { |
|||
position: relative; /* Vytvoří kontext pro absolute */ |
|||
} |
|||
|
|||
.badge { |
|||
position: absolute; |
|||
top: -10px; |
|||
right: -10px; |
|||
background: var(--danger-color); |
|||
color: white; |
|||
padding: 0.5rem 1rem; |
|||
border-radius: 20px; |
|||
} |
|||
``` |
|||
|
|||
## CSS Proměnné použití |
|||
|
|||
```css |
|||
.btn-primary { |
|||
background: linear-gradient( |
|||
135deg, |
|||
var(--primary-color), |
|||
var(--secondary-color) |
|||
); |
|||
color: var(--white); |
|||
padding: var(--spacing-sm) var(--spacing-md); |
|||
} |
|||
``` |
|||
|
|||
## Tips & Tricks |
|||
|
|||
### 1. Responzivní typografie s clamp() |
|||
```css |
|||
h1 { |
|||
font-size: clamp(2rem, 5vw, 4rem); |
|||
} |
|||
``` |
|||
|
|||
### 2. Aspect ratio pro obrázky |
|||
```css |
|||
.image-container { |
|||
aspect-ratio: 16/9; |
|||
overflow: hidden; |
|||
} |
|||
``` |
|||
|
|||
### 3. Flexbox centering |
|||
```css |
|||
.centered { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
min-height: 100vh; |
|||
} |
|||
``` |
|||
|
|||
### 4. Grid auto-fit |
|||
```css |
|||
.grid { |
|||
display: grid; |
|||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); |
|||
gap: 2rem; |
|||
} |
|||
``` |
|||
|
|||
## Checklist před odevzdáním |
|||
|
|||
- [ ] Všechny sémantické HTML5 elementy použity |
|||
- [ ] CSS Grid pro alespoň 2 sekce |
|||
- [ ] Flexbox pro alespoň 2 sekce |
|||
- [ ] Všechny 4 typy positioning použity |
|||
- [ ] Minimálně 3 media queries |
|||
- [ ] Formulář s funkční validací |
|||
- [ ] Smooth scroll implementován |
|||
- [ ] Scroll to top button funguje |
|||
- [ ] Použity CSS proměnné |
|||
- [ ] Použity rem/em jednotky (ne jen px) |
|||
- [ ] Hover efekty na interaktivních prvcích |
|||
- [ ] Animace při načtení stránky |
|||
- [ ] Responzivní na všech zařízeních |
|||
- [ ] Kód je komentovaný |
|||
- [ ] Žádné console errory |
|||
|
|||
## Hodnocení |
|||
|
|||
### Základní požadavky (70 bodů) |
|||
- HTML struktura (10 bodů) |
|||
- CSS Grid (10 bodů) |
|||
- Flexbox (10 bodů) |
|||
- Positioning (10 bodů) |
|||
- Media queries (10 bodů) |
|||
- JavaScript validace (10 bodů) |
|||
- Scroll efekty (10 bodů) |
|||
|
|||
### Pokročilé funkce (20 bodů) |
|||
- CSS proměnné (5 bodů) |
|||
- Animace (5 bodů) |
|||
- Pokročilé selektory (5 bodů) |
|||
- Clean code (5 bodů) |
|||
|
|||
### Bonus (10 bodů) |
|||
- Extra funkce (modal, accordion, atd.) |
|||
- Výjimečný design |
|||
- Originální nápady |
|||
|
|||
**Celkem: 100 bodů (+10 bonus)** |
|||
|
|||
## Užitečné zdroje |
|||
|
|||
- MDN Web Docs: https://developer.mozilla.org/ |
|||
- CSS Tricks: https://css-tricks.com/ |
|||
- Can I Use: https://caniuse.com/ |
|||
- Coolors (palety barev): https://coolors.co/ |
|||
- Google Fonts: https://fonts.google.com/ |
|||
|
|||
Hodně štěstí! 🚀 |
|||
@ -0,0 +1,166 @@ |
|||
# AI 04 - Komplexní Bootstrap Prep Projekt |
|||
|
|||
## 🎯 Cíl projektu |
|||
Komplexní projekt kombinující VŠECHNY naučené koncepty. Po dokončení tohoto projektu budete připraveni na Bootstrap! |
|||
|
|||
## 📝 Zadání |
|||
|
|||
Vytvořte **Responzivní Landing Page pro fiktivní produkt** (např. fitness aplikace, e-learning platforma, nebo jakýkoliv produkt dle vlastního výběru). |
|||
|
|||
### Požadavky na projekt: |
|||
|
|||
## 1️⃣ HTML - Sémantická struktura |
|||
|
|||
Použijte tyto sémantické elementy: |
|||
- `<nav>` - Fixní navigace s logem a menu |
|||
- `<header>` - Hero sekce s call-to-action |
|||
- `<main>` obsahující: |
|||
- `<section id="features">` - 3-6 features (ikony + text) |
|||
- `<section id="pricing">` - 3 cenové karty |
|||
- `<section id="testimonials">` - 3 recenze zákazníků |
|||
- `<section id="contact">` - Kontaktní formulář |
|||
- `<aside>` - Boční panel s quick links (sticky) |
|||
- `<footer>` - Zápatí s odkazy |
|||
|
|||
## 2️⃣ CSS - Layout & Design |
|||
|
|||
### Grid Layout: |
|||
- Features sekce: CSS Grid, 3 sloupce (desktop), 2 (tablet), 1 (mobil) |
|||
- Pricing karty: CSS Grid, 3 sloupce s gap 2rem |
|||
|
|||
### Flexbox: |
|||
- Navigace: flex s space-between |
|||
- Footer: flex s justify-content: space-around |
|||
- Testimonials: flex s flex-wrap |
|||
|
|||
### Positioning: |
|||
- `position: fixed` - Navigace |
|||
- `position: sticky` - Aside |
|||
- `position: absolute` - Badge "NEJLEPŠÍ VOLBA!" na jedné cenové kartě |
|||
- `position: relative` - Kontejner pro badge |
|||
|
|||
### Responzivita: |
|||
- Mobile first approach! |
|||
- Breakpoints: 480px, 768px, 1024px |
|||
- Media queries pro všechny sekce |
|||
|
|||
### Design: |
|||
- Použijte CSS proměnné (custom properties): |
|||
```css |
|||
:root { |
|||
--primary-color: #667eea; |
|||
--secondary-color: #764ba2; |
|||
--text-color: #333; |
|||
--bg-color: #f8f9fa; |
|||
} |
|||
``` |
|||
- Jednotky: rem, em, vh, vw (ne jen px!) |
|||
- Gradienty na pozadí |
|||
- Box shadows pro depth |
|||
- Hover efekty s transitions |
|||
- Animations (fadeIn, slideIn) |
|||
|
|||
## 3️⃣ JavaScript - Interaktivita |
|||
|
|||
### Formulář s validací: |
|||
- Jméno (min 3 znaky) |
|||
- Email (validní formát) |
|||
- Zpráva (min 10 znaků) |
|||
- Real-time validace pomocí `addEventListener` |
|||
- Visual feedback (červená/zelená) |
|||
|
|||
### Scroll efekty: |
|||
- Smooth scroll k sekcím při kliknutí na menu |
|||
- "Scroll to top" tlačítko (zobrazí se po scrollování) |
|||
- Změna barvy navigace při scrollování |
|||
|
|||
### Interaktivní features: |
|||
- Pricing toggle: měsíční/roční ceny (switch button) |
|||
- FAQ accordion (kliknutí → otevře/zavře odpověď) |
|||
- Modal okno pro "Více informací" tlačítko |
|||
|
|||
### Bonus: |
|||
- Counter animace (číselné statistiky se animují od 0) |
|||
- Lazy loading obrázků |
|||
- Dark mode toggle |
|||
|
|||
## 4️⃣ Pokročilé CSS selektory |
|||
|
|||
Použijte minimálně: |
|||
- `:nth-child()` - styling každé druhé karty |
|||
- `:hover`, `:focus`, `:active` |
|||
- `:first-child`, `:last-child` |
|||
- `::before`, `::after` - pro dekorativní elementy |
|||
- Attribute selectors - `[href^="http"]` pro externí odkazy |
|||
|
|||
## 📐 Struktura projektu |
|||
|
|||
``` |
|||
ai_04_prep_bootstrap/ |
|||
├── index.html |
|||
├── css/ |
|||
│ ├── style.css |
|||
│ └── animations.css |
|||
├── js/ |
|||
│ ├── main.js |
|||
│ ├── validation.js |
|||
│ └── scroll.js |
|||
└── images/ |
|||
└── (vaše obrázky) |
|||
``` |
|||
|
|||
## 💡 Co tento projekt procvičuje: |
|||
|
|||
### HTML: |
|||
✓ Sémantické elementy |
|||
✓ Formuláře |
|||
✓ Strukturu moderní webové stránky |
|||
|
|||
### CSS: |
|||
✓ Grid & Flexbox |
|||
✓ Positioning (všechny typy) |
|||
✓ Media queries |
|||
✓ CSS proměnné |
|||
✓ Jednotky (rem, em, vh, vw) |
|||
✓ Gradienty, shadows, transitions |
|||
✓ Animations |
|||
✓ Pokročilé selektory |
|||
|
|||
### JavaScript: |
|||
✓ addEventListener |
|||
✓ DOM manipulace |
|||
✓ Form validation |
|||
✓ Event handling |
|||
✓ Podmínky a cykly |
|||
✓ Funkce |
|||
|
|||
## 🎨 Design inspirace: |
|||
- https://www.awwwards.com/ |
|||
- https://dribbble.com/ |
|||
- Bootstrap examples (ale NEPOUŽÍVEJTE Bootstrap!) |
|||
|
|||
## ⏱️ Odhadovaný čas: 4-6 hodin |
|||
|
|||
## 🏆 Bonus úkoly (nepovinné): |
|||
1. Přidejte animaci AOS (Animate On Scroll) - při scrollování prvky plynule přijíždějí |
|||
2. Implementujte newsletter signup s AJAX (fake API endpoint) |
|||
3. Vytvořte carousel/slider pro testimonials (bez knihoven!) |
|||
4. Přidejte Easter egg (např. Konami kód) |
|||
5. PWA features (manifest.json, service worker) |
|||
|
|||
## 📚 Co se naučíte pro Bootstrap: |
|||
Po dokončení tohoto projektu budete rozumět: |
|||
- Jak funguje responzivní grid systém → Bootstrap grid |
|||
- Jak fungují utility třídy → Bootstrap utilities |
|||
- Jak se stylují komponenty → Bootstrap components |
|||
- Jak funguje JavaScript interaktivita → Bootstrap JS |
|||
- Mobile-first přístup → Bootstrap philosophy |
|||
|
|||
## 🚀 Po dokončení: |
|||
Gratulujeme! Jste připraveni na Bootstrap. Bootstrap vám nyní ušetří čas tím, že poskytuje: |
|||
- Předpřipravený grid systém (místo vašeho CSS Grid/Flexbox) |
|||
- Předpřipravené komponenty (tlačítka, karty, navigace) |
|||
- Předpřipravené utility třídy (margin, padding, colors) |
|||
- Responzivitu "out of the box" |
|||
|
|||
Ale díky tomuto projektu rozumíte, co se děje "pod kapotou"! |
|||
@ -0,0 +1,42 @@ |
|||
/* AI 04 - CSS Animace */ |
|||
|
|||
/* ============================================ |
|||
KEYFRAME ANIMATIONS |
|||
============================================ */ |
|||
|
|||
/* TODO: FadeIn animace */ |
|||
@keyframes fadeIn { |
|||
/* from { opacity: 0; } */ |
|||
/* to { opacity: 1; } */ |
|||
} |
|||
|
|||
/* TODO: SlideIn animace */ |
|||
@keyframes slideInUp { |
|||
/* from { transform: translateY(50px); opacity: 0; } */ |
|||
/* to { transform: translateY(0); opacity: 1; } */ |
|||
} |
|||
|
|||
/* TODO: Bounce animace */ |
|||
@keyframes bounce { |
|||
/* 0%, 20%, 50%, 80%, 100% { transform: translateY(0); } */ |
|||
/* 40% { transform: translateY(-20px); } */ |
|||
/* 60% { transform: translateY(-10px); } */ |
|||
} |
|||
|
|||
/* TODO: Pulse animace (pro tlačítka) */ |
|||
@keyframes pulse { |
|||
/* 0% { transform: scale(1); } */ |
|||
/* 50% { transform: scale(1.05); } */ |
|||
/* 100% { transform: scale(1); } */ |
|||
} |
|||
|
|||
/* TODO: Shake animace (pro chyby) */ |
|||
@keyframes shake { |
|||
|
|||
} |
|||
|
|||
/* ============================================ |
|||
UTILITY TŘÍDY PRO ANIMACE |
|||
============================================ */ |
|||
|
|||
/* TODO: Přidejte třídy jako .fade-in, .slide-in, atd. */ |
|||
@ -0,0 +1,131 @@ |
|||
/* AI 04 - Komplexní Bootstrap Prep Projekt */ |
|||
|
|||
/* ============================================ |
|||
CSS PROMĚNNÉ (Custom Properties) |
|||
============================================ */ |
|||
:root { |
|||
/* Barvy */ |
|||
--primary-color: #667eea; |
|||
--secondary-color: #764ba2; |
|||
--success-color: #2ecc71; |
|||
--danger-color: #e74c3c; |
|||
--text-color: #333; |
|||
--text-light: #666; |
|||
--bg-color: #f8f9fa; |
|||
--white: #ffffff; |
|||
|
|||
/* Spacing */ |
|||
--spacing-xs: 0.5rem; |
|||
--spacing-sm: 1rem; |
|||
--spacing-md: 2rem; |
|||
--spacing-lg: 4rem; |
|||
--spacing-xl: 6rem; |
|||
|
|||
/* Typography */ |
|||
--font-primary: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|||
--font-size-base: 1rem; |
|||
--font-size-lg: 1.25rem; |
|||
--font-size-xl: 2rem; |
|||
--font-size-xxl: 3rem; |
|||
|
|||
/* Breakpoints (pro JavaScript) */ |
|||
--breakpoint-sm: 480px; |
|||
--breakpoint-md: 768px; |
|||
--breakpoint-lg: 1024px; |
|||
} |
|||
|
|||
/* ============================================ |
|||
RESET & BASE STYLES |
|||
============================================ */ |
|||
/* TODO: Přidejte reset styly */ |
|||
|
|||
|
|||
/* ============================================ |
|||
NAVIGACE (position: fixed) |
|||
============================================ */ |
|||
/* TODO: Vytvořte fixní navigaci nahoře */ |
|||
|
|||
|
|||
/* ============================================ |
|||
HEADER / HERO SEKCE |
|||
============================================ */ |
|||
/* TODO: Hero sekce s gradientem, vycentrovaný text */ |
|||
|
|||
|
|||
/* ============================================ |
|||
FEATURES SEKCE (CSS GRID) |
|||
============================================ */ |
|||
/* TODO: Grid layout pro features */ |
|||
/* Desktop: 3 sloupce */ |
|||
/* Tablet: 2 sloupce */ |
|||
/* Mobil: 1 sloupec */ |
|||
|
|||
|
|||
/* ============================================ |
|||
PRICING SEKCE (CSS GRID + POSITIONING) |
|||
============================================ */ |
|||
/* TODO: Grid layout pro cenové karty */ |
|||
/* Použijte position: relative pro kontejner */ |
|||
/* Použijte position: absolute pro "NEJLEPŠÍ VOLBA!" badge */ |
|||
|
|||
|
|||
/* ============================================ |
|||
TESTIMONIALS SEKCE (FLEXBOX) |
|||
============================================ */ |
|||
/* TODO: Flex layout s flex-wrap */ |
|||
|
|||
|
|||
/* ============================================ |
|||
CONTACT SEKCE (FORMULÁŘ) |
|||
============================================ */ |
|||
/* TODO: Styling formuláře s validačními stavy */ |
|||
|
|||
|
|||
/* ============================================ |
|||
ASIDE (position: sticky) |
|||
============================================ */ |
|||
/* TODO: Sticky sidebar */ |
|||
|
|||
|
|||
/* ============================================ |
|||
FOOTER |
|||
============================================ */ |
|||
/* TODO: Footer s flexboxem */ |
|||
|
|||
|
|||
/* ============================================ |
|||
SCROLL TO TOP BUTTON |
|||
============================================ */ |
|||
/* TODO: Button pro scroll nahoru (position: fixed) */ |
|||
|
|||
|
|||
/* ============================================ |
|||
POKROČILÉ SELEKTORY |
|||
============================================ */ |
|||
|
|||
/* TODO: Použijte nth-child pro alternativní styling */ |
|||
/* .feature-card:nth-child(even) {} */ |
|||
|
|||
|
|||
/* TODO: Použijte ::before a ::after pro dekoraci */ |
|||
|
|||
|
|||
/* TODO: Styling externích odkazů */ |
|||
/* a[href^="http"] {} */ |
|||
|
|||
|
|||
/* ============================================ |
|||
MEDIA QUERIES - RESPONZIVITA |
|||
============================================ */ |
|||
|
|||
/* Mobile First! */ |
|||
|
|||
/* Tablet - 768px */ |
|||
@media screen and (min-width: 768px) { |
|||
/* TODO */ |
|||
} |
|||
|
|||
/* Desktop - 1024px */ |
|||
@media screen and (min-width: 1024px) { |
|||
/* TODO */ |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<meta name="description" content="FitPro - Vaše cesta k lepší kondici"> |
|||
<title>FitPro - Fitness Aplikace</title> |
|||
<link rel="stylesheet" href="css/style.css"> |
|||
<link rel="stylesheet" href="css/animations.css"> |
|||
</head> |
|||
<body> |
|||
<!-- TODO: Začněte zde vytvářet landing page --> |
|||
|
|||
<!-- 1. NAVIGACE (position: fixed) --> |
|||
<!-- nav#navbar --> |
|||
|
|||
|
|||
<!-- 2. HEADER / HERO SEKCE --> |
|||
<!-- header#hero --> |
|||
|
|||
|
|||
<!-- 3. MAIN - Hlavní obsah --> |
|||
<!-- <main> --> |
|||
|
|||
<!-- 3a. FEATURES SEKCE (CSS Grid) --> |
|||
<!-- section#features --> |
|||
|
|||
|
|||
<!-- 3b. PRICING SEKCE (CSS Grid) --> |
|||
<!-- section#pricing --> |
|||
|
|||
|
|||
<!-- 3c. TESTIMONIALS SEKCE (Flexbox) --> |
|||
<!-- section#testimonials --> |
|||
|
|||
|
|||
<!-- 3d. KONTAKT SEKCE (Formulář s validací) --> |
|||
<!-- section#contact --> |
|||
|
|||
|
|||
<!-- </main> --> |
|||
|
|||
|
|||
<!-- 4. ASIDE (position: sticky) --> |
|||
<!-- aside#quicklinks --> |
|||
|
|||
|
|||
<!-- 5. FOOTER --> |
|||
<!-- footer --> |
|||
|
|||
|
|||
<!-- 6. SCROLL TO TOP BUTTON (skrytý, zobrazí se při scrollování) --> |
|||
<!-- <button id="scrollToTop" class="scroll-top-btn">↑</button> --> |
|||
|
|||
|
|||
<!-- JavaScript soubory --> |
|||
<script src="js/validation.js"></script> |
|||
<script src="js/scroll.js"></script> |
|||
<script src="js/main.js"></script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,37 @@ |
|||
// AI 04 - Main JavaScript
|
|||
|
|||
console.log("Main.js načten"); |
|||
|
|||
// ========================================
|
|||
// PRICING TOGGLE (měsíční/roční)
|
|||
// ========================================
|
|||
|
|||
// TODO: Implementujte přepínání mezi měsíčními a ročními cenami
|
|||
|
|||
|
|||
// ========================================
|
|||
// FAQ ACCORDION
|
|||
// ========================================
|
|||
|
|||
// TODO: Implementujte accordion (kliknutí otevře/zavře odpověď)
|
|||
|
|||
|
|||
// ========================================
|
|||
// MODAL OKNO
|
|||
// ========================================
|
|||
|
|||
// TODO: Implementujte modal okno pro "Více informací"
|
|||
|
|||
|
|||
// ========================================
|
|||
// COUNTER ANIMACE
|
|||
// ========================================
|
|||
|
|||
// TODO: Animujte čísla od 0 do cílové hodnoty
|
|||
|
|||
|
|||
// ========================================
|
|||
// DARK MODE TOGGLE (BONUS)
|
|||
// ========================================
|
|||
|
|||
// TODO: Implementujte přepínání mezi světlým a tmavým režimem
|
|||
@ -0,0 +1,36 @@ |
|||
// AI 04 - Scroll efekty
|
|||
|
|||
console.log("Scroll.js načten"); |
|||
|
|||
// ========================================
|
|||
// SMOOTH SCROLL K SEKCÍM
|
|||
// ========================================
|
|||
|
|||
// TODO: Implementujte smooth scroll při kliknutí na menu linky
|
|||
// document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|||
// anchor.addEventListener('click', function (e) {
|
|||
// e.preventDefault();
|
|||
// // ... smooth scroll
|
|||
// });
|
|||
// });
|
|||
|
|||
|
|||
// ========================================
|
|||
// SCROLL TO TOP BUTTON
|
|||
// ========================================
|
|||
|
|||
// TODO: Zobrazit/skrýt "Scroll to top" tlačítko při scrollování
|
|||
|
|||
|
|||
// ========================================
|
|||
// ZMĚNA NAVIGACE PŘI SCROLLOVÁNÍ
|
|||
// ========================================
|
|||
|
|||
// TODO: Změnit barvu/styl navigace když uživatel scrolluje dolů
|
|||
|
|||
|
|||
// ========================================
|
|||
// ANIMATE ON SCROLL (BONUS)
|
|||
// ========================================
|
|||
|
|||
// TODO: Přidejte třídu "visible" elementům když se dostanou do viewportu
|
|||
@ -0,0 +1,48 @@ |
|||
// AI 04 - Validace formuláře
|
|||
|
|||
console.log("Validation.js načten"); |
|||
|
|||
// TODO: Implementujte validaci kontaktního formuláře
|
|||
// Požadavky:
|
|||
// - Jméno: min 3 znaky
|
|||
// - Email: validní formát
|
|||
// - Zpráva: min 10 znaků
|
|||
// - Real-time validace pomocí addEventListener
|
|||
// - Visual feedback (červená/zelená border)
|
|||
|
|||
// ========================================
|
|||
// ZÍSKÁNÍ REFERENCÍ NA ELEMENTY
|
|||
// ========================================
|
|||
|
|||
// TODO: const contactForm = document.getElementById("contactForm");
|
|||
|
|||
|
|||
// ========================================
|
|||
// EVENT LISTENERS
|
|||
// ========================================
|
|||
|
|||
// TODO: Přidejte event listenery pro input eventy
|
|||
|
|||
|
|||
// ========================================
|
|||
// VALIDAČNÍ FUNKCE
|
|||
// ========================================
|
|||
|
|||
// TODO: function validateContactName() {}
|
|||
// TODO: function validateContactEmail() {}
|
|||
// TODO: function validateContactMessage() {}
|
|||
|
|||
|
|||
// ========================================
|
|||
// HELPER FUNKCE
|
|||
// ========================================
|
|||
|
|||
// TODO: function showError(element, message) {}
|
|||
// TODO: function showSuccess(element) {}
|
|||
|
|||
|
|||
// ========================================
|
|||
// SUBMIT HANDLER
|
|||
// ========================================
|
|||
|
|||
// TODO: function handleContactSubmit(e) {}
|
|||
@ -0,0 +1,177 @@ |
|||
# Nový Bootstrap Projekt |
|||
|
|||
## 🎯 Účel projektu |
|||
|
|||
Tento projekt slouží jako **prázdná šablona** pro vytváření nových Bootstrap projektů. Obsahuje základní připojení Bootstrap CSS a JS. |
|||
|
|||
## 📚 Co projekt obsahuje |
|||
|
|||
- **Bootstrap 5.x** - lokální soubory CSS a JS |
|||
- **Základní HTML struktura** - připravená pro vývoj |
|||
- **Viewport meta tag** - pro responzivitu |
|||
|
|||
## 📂 Soubory v projektu |
|||
|
|||
- `index.html` - základní HTML s připojeným Bootstrapem |
|||
- `css/bootstrap.css` - Bootstrap CSS (lokální soubor) |
|||
- `js/bootstrap.js` - Bootstrap JavaScript (lokální soubor) |
|||
|
|||
## 🚀 Jak použít tento projekt |
|||
|
|||
### Krok 1: Zkopírujte složku |
|||
```bash |
|||
# Zkopírujte celou složku novyprojekt_bootstrap |
|||
# Přejmenujte na název vašeho projektu, např.: |
|||
- muj_novy_projekt/ |
|||
- portfolio_stranky/ |
|||
- eshop_projekt/ |
|||
``` |
|||
|
|||
### Krok 2: Upravte index.html |
|||
```html |
|||
<!DOCTYPE html> |
|||
<html lang="cs"> <!-- změňte jazyk na cs --> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Můj projekt</title> <!-- změňte title --> |
|||
<link rel="stylesheet" href="css/bootstrap.css"> |
|||
</head> |
|||
<body> |
|||
<div class="container"> |
|||
<h1 class="display-1">Hello World with Bootstrap!</h1> |
|||
<!-- Začněte psát váš kód zde --> |
|||
</div> |
|||
|
|||
<script src="js/bootstrap.js"></script> |
|||
</body> |
|||
</html> |
|||
``` |
|||
|
|||
### Krok 3: Začněte vyvíjet |
|||
|
|||
**Přidejte Bootstrap komponenty:** |
|||
```html |
|||
<!-- Navigace --> |
|||
<nav class="navbar navbar-expand-lg navbar-light bg-light"> |
|||
<div class="container"> |
|||
<a class="navbar-brand" href="#">Logo</a> |
|||
</div> |
|||
</nav> |
|||
|
|||
<!-- Grid --> |
|||
<div class="container"> |
|||
<div class="row"> |
|||
<div class="col-md-6">Sloupec 1</div> |
|||
<div class="col-md-6">Sloupec 2</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Tlačítka --> |
|||
<button class="btn btn-primary">Primary</button> |
|||
<button class="btn btn-success">Success</button> |
|||
|
|||
<!-- Karty --> |
|||
<div class="card" style="width: 18rem;"> |
|||
<div class="card-body"> |
|||
<h5 class="card-title">Název karty</h5> |
|||
<p class="card-text">Text karty</p> |
|||
<a href="#" class="btn btn-primary">Tlačítko</a> |
|||
</div> |
|||
</div> |
|||
``` |
|||
|
|||
## 💡 Užitečné Bootstrap třídy |
|||
|
|||
### Container a Grid: |
|||
```html |
|||
<div class="container"> <!-- Fixní šířka, centrovaný --> |
|||
<div class="container-fluid"> <!-- 100% šířka --> |
|||
|
|||
<div class="row"> <!-- Řádek --> |
|||
<div class="col-md-6"> <!-- 50% na tabletu+ --> |
|||
``` |
|||
|
|||
### Utility třídy: |
|||
```html |
|||
<!-- Margin a Padding --> |
|||
m-3 = margin všude |
|||
mt-2 = margin-top |
|||
px-4 = padding vlevo a vpravo |
|||
|
|||
<!-- Barvy --> |
|||
text-primary = modrý text |
|||
bg-danger = červené pozadí |
|||
|
|||
<!-- Display --> |
|||
d-flex = display: flex |
|||
d-none d-md-block = skryto na mobilu, zobrazeno na tabletu+ |
|||
``` |
|||
|
|||
### Komponenty: |
|||
```html |
|||
<!-- Buttons --> |
|||
<button class="btn btn-primary">Primary</button> |
|||
|
|||
<!-- Alerts --> |
|||
<div class="alert alert-success">Success!</div> |
|||
|
|||
<!-- Cards --> |
|||
<div class="card">...</div> |
|||
|
|||
<!-- Modal --> |
|||
<button data-bs-toggle="modal" data-bs-target="#myModal"> |
|||
Open Modal |
|||
</button> |
|||
``` |
|||
|
|||
## 🔗 Bootstrap dokumentace |
|||
|
|||
- **Oficiální dokumentace:** https://getbootstrap.com/docs/5.3/ |
|||
- **Bootstrap Icons:** https://icons.getbootstrap.com/ |
|||
- **Bootstrap Examples:** https://getbootstrap.com/docs/5.3/examples/ |
|||
|
|||
## 📚 Související lekce |
|||
|
|||
Před použitím tohoto projektu se ujistěte, že jste prošli: |
|||
- **13_bootstrap_intro** - úvod do Bootstrapu |
|||
- **14_bootstrap_layout** - Bootstrap layout |
|||
- **15_bootstrap_components** - Bootstrap komponenty |
|||
|
|||
## 💡 Tip pro studenty |
|||
|
|||
**Kdy použít tento projekt:** |
|||
- ✅ Nový Bootstrap projekt od nuly |
|||
- ✅ Prototypování webové stránky |
|||
- ✅ Cvičení Bootstrap komponent |
|||
- ✅ Školní projekty |
|||
|
|||
**Alternativa - CDN (online Bootstrap):** |
|||
```html |
|||
<!-- Místo lokálních souborů můžete použít CDN --> |
|||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> |
|||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> |
|||
``` |
|||
|
|||
**Výhody lokálních souborů:** |
|||
- Funguje offline |
|||
- Rychlejší (není potřeba stahovat z internetu) |
|||
|
|||
**Výhody CDN:** |
|||
- Menší velikost projektu |
|||
- Možná už v cache prohlížeče |
|||
|
|||
## ⚠️ Důležité poznámky |
|||
|
|||
1. **Bootstrap.js vyžaduje** - carousel, modal, dropdown fungují jen s připojeným JS |
|||
2. **Viewport meta tag je povinný** - bez něj responzivita nebude fungovat |
|||
3. **jQuery není potřeba** - Bootstrap 5 už jQuery nepotřebuje |
|||
|
|||
## 🎯 Další kroky |
|||
|
|||
1. Prozkoumejte [Bootstrap dokumentaci](https://getbootstrap.com/) |
|||
2. Vyzkoušejte různé komponenty |
|||
3. Vytvořte vlastní projekt pomocí této šablony |
|||
4. Experimentujte s utility třídami |
|||
|
|||
Hodně štěstí s vaším projektem! 🚀 |
|||
Loading…
Reference in new issue