Warung makan kecil umumnya mencari cara termurah untuk tampil di internet: satu halaman yang memuat menu beserta harganya, alamat, nomor telepon, jam buka, dan sarana memesan. Halaman semacam itu tidak butuh server khusus; HTML, CSS, dan sedikit JavaScript saja mampu menopangnya. Proyek ini membangun halaman tersebut untuk Warung Melati, warung masakan rumahan Sunda milik Dewi Lestari di Bandung.
Hasil Akhir yang Dibangun #
Target akhirnya adalah satu halaman Warung Melati yang siap dibagikan kepada pelanggan. Fitur yang kita bangun secara bertahap:
- Dokumen valid dengan metadata lengkap (charset, viewport, title, description).
- Header hero berisi logo SVG, nama warung, dan tagline.
- Menu makanan dalam dl yang memasangkan nama hidangan dengan keterangan dan harga.
- Section kontak dengan address, tautan tel: dan mailto:, serta tabel jam buka.
- Tampilan hangat dari styles/style.css dengan layout dua kolom sederhana.
- Form pemesanan mini: validasi native, perhitungan total lewat JavaScript, dan dialog ringkasan.
Prasyarat #
Proyek ini merangkai konsep dari section sebelumnya; baca dahulu bila materinya masih asing:
- Section Semantic HTML: header, main, footer, section, dan address.
- Section Tables: table, caption, dan th scope.
- Section HTML dan CSS: selector, custom properties, dan flexbox.
- Section Forms serta Form Validation: label, select, required, min, dan max.
- Section HTML dan JavaScript serta Interactive Elements: addEventListener dan dialog.
Empat Bagian Proyek #
Kerjakan keempat bagian berurutan; setiap bagian memakai hasil bagian sebelumnya:
| Bagian | Fokus |
|---|---|
| Bagian 1: Menyusun Struktur Halaman | Kerangka valid dan header hero |
| Bagian 2: Menu dan Kontak | dl menu, address dengan tel:, tabel jam buka |
| Bagian 3: Styling Dasar | Palet hangat, tipografi menu, dua kolom |
| Bagian 4: Interaksi Pemesanan Sederhana | Form mini, validasi native, dialog ringkasan |
Memakai File Pendukung #
Tiga folder proyek menyimpan berkas pendukung. Susun salinan lokalnya mengikuti pohon berikut:
website-restoran/
├── assets/
│ └── logo-resto.svg
├── styles/
│ └── style.css
├── tests/
│ └── cek-struktur.html
├── part-1-struktur-halaman/
│ └── restoran.html
├── part-2-menu-dan-kontak/
│ └── restoran-konten.html
├── part-3-styling-dasar/
│ └── restoran-styling.html
└── part-4-interaksi-pemesanan-sederhana/
├── restoran-pesan.html
└── pesan.js- assets/logo-resto.svg: logo bundar warung untuk header setiap tahap.
- styles/style.css: stylesheet final dari Bagian 3, dipakai Bagian 4.
- tests/cek-struktur.html: checklist sepuluh butir; kemajuan tersimpan di localStorage.
Unduh contoh tiap bagian lewat tautan pada header code block, lalu letakkan sesuai pohon di atas agar jalur relatif seperti ../assets/logo-resto.svg dan ../styles/style.css tetap benar.
Referensi resmi untuk pendalaman:
Tahap 1 dari proyek Website Restoran.
Buka → # Bagian 2: Menu dan KontakTahap 2 dari proyek Website Restoran.
Buka → # Bagian 3: Styling DasarTahap 3 dari proyek Website Restoran.
Buka → # Bagian 4: Interaksi Pemesanan SederhanaTahap 4 dari proyek Website Restoran.
Buka →Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
styles/style.css
Unduh berkas/* Stylesheet proyek Website Restoran - ditulis pada Bagian 3, dipakai Bagian 3 dan 4 */
:root {
--warna-utama: #b45309;
--warna-utama-tua: #7c3a06;
--warna-teks: #292524;
--warna-latar: #fbf3e4;
--warna-putih: #ffffff;
--warna-garis: #ecd9bd;
--jarak: 16px;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: system-ui, sans-serif;
line-height: 1.6;
color: var(--warna-teks);
background-color: var(--warna-latar);
}
header.hero {
background-color: var(--warna-utama);
color: var(--warna-putih);
padding: 48px var(--jarak);
text-align: center;
}
header.hero img {
border-radius: 50%;
}
header.hero h1 {
margin: 8px 0 4px;
font-family: Georgia, serif;
font-size: 2rem;
}
header.hero p {
margin: 0;
font-style: italic;
}
main {
max-width: 960px;
margin: 0 auto;
padding: var(--jarak);
display: flex;
flex-wrap: wrap;
gap: var(--jarak);
align-items: flex-start;
}
main section {
flex: 1 1 300px;
padding: var(--jarak);
background-color: var(--warna-putih);
border-radius: 8px;
}
main #menu {
flex: 2 1 380px;
}
h2 {
margin-top: 0;
font-family: Georgia, serif;
color: var(--warna-utama-tua);
}
dl.menu dt {
font-weight: bold;
}
dl.menu dd {
margin: 0 0 var(--jarak);
padding-bottom: 8px;
border-bottom: 1px dashed var(--warna-garis);
}
address {
font-style: normal;
line-height: 1.9;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.95rem;
}
caption {
margin-bottom: 8px;
text-align: left;
font-size: 0.9rem;
color: #6b7280;
}
th,
td {
padding: 8px;
border: 1px solid var(--warna-garis);
text-align: left;
}
form div {
margin-bottom: var(--jarak);
}
label {
display: block;
margin-bottom: 4px;
font-weight: bold;
}
input,
select {
width: 100%;
padding: 8px;
border: 1px solid var(--warna-garis);
border-radius: 6px;
font-size: 1rem;
background-color: var(--warna-putih);
color: var(--warna-teks);
}
button {
padding: 10px 20px;
border: none;
border-radius: 6px;
font-size: 1rem;
background-color: var(--warna-utama);
color: var(--warna-putih);
cursor: pointer;
}
dialog {
max-width: 360px;
padding: var(--jarak);
border: none;
border-radius: 8px;
}
dialog::backdrop {
background-color: rgba(41, 37, 36, 0.5);
}
footer {
background-color: var(--warna-utama-tua);
color: var(--warna-putih);
}
footer p {
margin: 0;
padding: var(--jarak);
text-align: center;
}
tests/cek-struktur.html
Unduh berkas<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checklist Pemeriksaan Website Restoran</title>
<style>
body {
font-family: system-ui, sans-serif;
max-width: 720px;
margin: 0 auto;
padding: 16px;
line-height: 1.6;
color: #1f2937;
}
h1 {
font-size: 1.4rem;
}
ul {
padding-left: 20px;
}
li {
margin-bottom: 8px;
}
#progres {
width: 100%;
height: 16px;
}
</style>
</head>
<body>
<header>
<img src="../assets/logo-resto.svg" alt="Logo Warung Melati" width="48" height="48">
<h1>Checklist Pemeriksaan Website Restoran</h1>
</header>
<p>Gunakan halaman ini untuk memeriksa hasil setiap Bagian proyek. Centang butir yang telah dipenuhi; kemajuan tersimpan otomatis di browser.</p>
<p id="ringkasan" aria-live="polite">0 dari 10 butir terpenuhi.</p>
<progress id="progres" value="0" max="10"></progress>
<ul>
<li><label><input type="checkbox" data-cek="1"> Dokumen dimulai dengan <code>doctype</code> dan <code>html lang="id"</code></label></li>
<li><label><input type="checkbox" data-cek="2"> Head memuat <code>meta charset</code>, <code>viewport</code>, <code>title</code>, dan <code>description</code></label></li>
<li><label><input type="checkbox" data-cek="3"> Header hero memuat logo, nama warung, dan tagline</label></li>
<li><label><input type="checkbox" data-cek="4"> Menu tersusun di dalam <code>dl</code> dengan harga pada setiap <code>dd</code></label></li>
<li><label><input type="checkbox" data-cek="5"> Kontak dibungkus <code>address</code> dengan tautan <code>tel:</code> dan <code>mailto:</code></label></li>
<li><label><input type="checkbox" data-cek="6"> Jam buka tersusun sebagai <code>table</code> dengan <code>caption</code> dan <code>th scope</code></label></li>
<li><label><input type="checkbox" data-cek="7"> Halaman terhubung ke stylesheet <code>styles/style.css</code></label></li>
<li><label><input type="checkbox" data-cek="8"> Form pemesanan memakai <code>label for</code>, <code>required</code>, serta <code>min</code> dan <code>max</code></label></li>
<li><label><input type="checkbox" data-cek="9"> Total pesanan dihitung JavaScript lalu ditampilkan pada elemen <code>dialog</code></label></li>
<li><label><input type="checkbox" data-cek="10"> Dialog ringkasan terbuka lewat submit dan tertutup tanpa menghalangi keyboard</label></li>
</ul>
<p>Sintaks seluruh file proyek juga dapat diperiksa dengan Nu Html Checker di <a href="https://validator.w3.org/nu/">validator.w3.org/nu</a>.</p>
<script>
const daftar = document.querySelectorAll("input[type='checkbox']");
const progres = document.querySelector("#progres");
const ringkasan = document.querySelector("#ringkasan");
const KUNCI = "cek-website-restoran";
function simpan() {
const status = [];
daftar.forEach(function (butir) {
status.push(butir.checked);
});
try {
localStorage.setItem(KUNCI, JSON.stringify(status));
} catch (galat) {
// penyimpanan tidak tersedia; status tetap berlaku selama halaman terbuka
}
}
function muat() {
try {
const status = JSON.parse(localStorage.getItem(KUNCI));
if (Array.isArray(status)) {
daftar.forEach(function (butir, indeks) {
butir.checked = status[indeks] === true;
});
}
} catch (galat) {
// biarkan semua butir pada keadaan awalnya
}
}
function perbarui() {
let terisi = 0;
daftar.forEach(function (butir) {
if (butir.checked) {
terisi += 1;
}
});
progres.value = terisi;
ringkasan.textContent = terisi + " dari " + daftar.length + " butir terpenuhi.";
}
muat();
perbarui();
daftar.forEach(function (butir) {
butir.addEventListener("change", function () {
perbarui();
simpan();
});
});
</script>
</body>
</html>