π Three Ways to Build a Website
π Static β pre-built files served as-is
βοΈ Dynamic (SSR) β server builds the page fresh each time
π API-Powered (CSR) β server sends data, browser builds the page
Modern web dev uses all three depending on the project.
π Static Websites
<!-- Infographic: Static Websites β pre-built files, no server logic, 16:9, responsive, synced timeline -->
<div class="infographic-staticsite">
<style>
.infographic-staticsite {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--muted: #b6afa0;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
width: 100%;
max-width: 1000px;
margin: 0 auto;
box-sizing: border-box;
aspect-ratio: 16 / 9;
display: flex;
flex-direction: column;
container-type: inline-size;
container-name: sscard;
}
.infographic-staticsite[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
--muted: #4a4740;
}
.infographic-staticsite * { box-sizing: border-box; }
.ss-stage {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: clamp(0.3rem, 2.5cqw, 1.2rem);
min-height: 0;
min-width: 0;
padding: clamp(0.5rem, 3cqw, 1.5rem);
}
/* --- endpoint nodes --- */
.ss-node {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(0.2rem, 1cqw, 0.45rem);
flex: 0 0 auto;
min-width: 0;
}
.ss-node-box {
width: clamp(48px, 13cqw, 100px);
height: clamp(48px, 13cqw, 100px);
border-radius: 50%;
border: 2px solid var(--line);
background: var(--paper-alt);
display: flex;
align-items: center;
justify-content: center;
color: var(--accent);
position: relative;
flex: 0 0 auto;
}
.ss-node-box svg { width: clamp(20px, 5.6cqw, 40px); height: clamp(20px, 5.6cqw, 40px); stroke: var(--accent); }
.ss-node-label { font-size: clamp(0.4rem, 1.6cqw, 0.78rem); font-weight: 700; white-space: nowrap; }
.ss-node-tag {
font-size: clamp(0.3rem, 1.1cqw, 0.58rem);
font-weight: 700;
color: var(--accent);
opacity: 0;
white-space: nowrap;
}
/* server: only a brief acknowledge flash (never a spinning "processing" ring β nothing runs) */
.ss-node.server .ss-node-box { animation: ss-server-ack 4s ease-in-out infinite; }
@keyframes ss-server-ack {
0%, 12% { border-color: var(--line); background: var(--paper-alt); }
15%, 20% { border-color: var(--accent); background: var(--accent-soft); }
24% { border-color: var(--line); background: var(--paper-alt); }
100% { border-color: var(--line); background: var(--paper-alt); }
}
/* visitor: pops once all files land together (~52%) */
.ss-node.visitor .ss-node-box { animation: ss-visitor-pop 4s cubic-bezier(.34,1.56,.64,1) infinite; }
@keyframes ss-visitor-pop {
0%, 50% { transform: scale(1); border-color: var(--line); background: var(--paper-alt); }
55% { transform: scale(1.16); border-color: var(--accent); background: var(--accent-soft); }
62% { transform: scale(1.04); border-color: var(--accent); background: var(--accent-soft); }
88% { transform: scale(1.04); border-color: var(--accent); background: var(--accent-soft); }
95%, 100% { transform: scale(1); border-color: var(--line); background: var(--paper-alt); }
}
.ss-node.visitor .ss-node-tag { animation: ss-visitor-tag 4s ease-in-out infinite; }
@keyframes ss-visitor-tag { 0%,53%{opacity:0;} 58%,86%{opacity:1;} 92%,100%{opacity:0;} }
/* --- pre-built file shelf, always static β nothing is generated on request --- */
.ss-shelf {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: clamp(0.15rem, 0.8cqw, 0.3rem);
width: clamp(70px, 18cqw, 130px);
}
.ss-shelf-item {
position: relative;
width: 100%;
aspect-ratio: 1;
border-radius: 6px;
border: 1.5px solid var(--line);
background: var(--paper-alt);
display: flex; align-items: center; justify-content: center;
}
.ss-shelf-item svg { width: 55%; height: 55%; stroke: var(--ink-soft); }
.ss-shelf-check {
position: absolute; bottom: -3px; right: -3px;
width: clamp(8px, 2cqw, 13px); height: clamp(8px, 2cqw, 13px);
border-radius: 50%;
background: var(--accent);
color: #fff;
font-size: clamp(5px, 1.3cqw, 8px);
font-weight: 900;
display: flex; align-items: center; justify-content: center;
}
.ss-shelf-label {
text-align: center;
font-size: clamp(0.32rem, 1.2cqw, 0.6rem);
font-weight: 700;
color: var(--ink-soft);
margin-bottom: clamp(0.15rem, 0.8cqw, 0.3rem);
}
/* --- "no server logic runs" badge β static, always shown --- */
.ss-nologic {
display: flex;
align-items: center;
gap: clamp(0.2rem, 1cqw, 0.35rem);
margin-top: clamp(0.25rem, 1.2cqw, 0.5rem);
padding: clamp(0.15rem, 0.8cqw, 0.3rem) clamp(0.35rem, 1.4cqw, 0.55rem);
border: 1px dashed var(--muted);
border-radius: 999px;
}
.ss-nologic-icon { position: relative; width: clamp(11px, 2.8cqw, 16px); height: clamp(11px, 2.8cqw, 16px); flex: 0 0 auto; }
.ss-nologic-icon svg { width: 100%; height: 100%; stroke: var(--muted); }
.ss-nologic-icon::after {
content: "";
position: absolute; left: -10%; top: 50%;
width: 120%; height: 1.6px;
background: var(--muted);
transform: translateY(-50%) rotate(-45deg);
}
.ss-nologic-text { font-size: clamp(0.28rem, 1.05cqw, 0.54rem); font-weight: 600; color: var(--ink-soft); white-space: nowrap; }
/* --- middle: request lane (top) + response lane (bottom) --- */
.ss-middle {
flex: 1 1 auto;
min-width: clamp(110px, 24cqw, 300px);
max-width: 330px;
display: flex;
flex-direction: column;
gap: clamp(0.7rem, 3.5cqw, 1.3rem);
}
.ss-lane { position: relative; display: flex; flex-direction: column; align-items: center; gap: clamp(0.12rem, 0.7cqw, 0.3rem); }
.ss-lane-label {
font-size: clamp(0.3rem, 1.2cqw, 0.58rem);
font-weight: 700;
color: var(--ink-soft);
white-space: nowrap;
opacity: 0;
}
.ss-lane.request .ss-lane-label { animation: ss-req-label 4s ease-in-out infinite; }
@keyframes ss-req-label { 0%,3%{opacity:0;} 6%,22%{opacity:1;} 28%,100%{opacity:0;} }
.ss-lane.response .ss-lane-label { animation: ss-res-label 4s ease-in-out infinite; }
@keyframes ss-res-label { 0%,26%{opacity:0;} 30%,50%{opacity:1;} 56%,100%{opacity:0;} }
.ss-track { position: relative; width: 100%; height: 2px; background: var(--line); }
.ss-track.request::after {
content: ""; position: absolute; right: -1px; top: 50%;
width: clamp(5px, 1.3cqw, 8px); height: clamp(5px, 1.3cqw, 8px);
border-top: 2px solid var(--line); border-right: 2px solid var(--line);
transform: translateY(-50%) rotate(45deg);
}
.ss-track.response::before {
content: ""; position: absolute; left: -1px; top: 50%;
width: clamp(5px, 1.3cqw, 8px); height: clamp(5px, 1.3cqw, 8px);
border-bottom: 2px solid var(--line); border-left: 2px solid var(--line);
transform: translateY(-50%) rotate(45deg);
}
.ss-dot {
position: absolute; top: 50%;
width: clamp(5px, 1.4cqw, 8px); height: clamp(5px, 1.4cqw, 8px);
border-radius: 50%;
background: var(--accent);
transform: translateY(-50%);
}
.ss-track.request .ss-dot { left: 0; animation: ss-req-travel 4s ease-in-out infinite; }
@keyframes ss-req-travel {
0%, 3% { left: 0%; opacity: 0; }
6% { opacity: 1; }
14% { left: calc(100% - 8px); opacity: 1; }
17%, 100%{ left: calc(100% - 8px); opacity: 0; }
}
/* response: all 6 files travel back together, same start, same arrival β nothing is staggered by "processing" */
.ss-chip {
position: absolute; top: 50%; right: 0;
width: clamp(8px, 2.1cqw, 13px); height: clamp(8px, 2.1cqw, 13px);
border-radius: 3px;
background: var(--accent);
transform: translateY(-50%);
}
.ss-chip:nth-child(1) { margin-top: -6px; }
.ss-chip:nth-child(2) { margin-top: -2px; }
.ss-chip:nth-child(3) { margin-top: 2px; }
.ss-chip:nth-child(4) { margin-top: 6px; }
.ss-chip { animation: ss-res-travel 4s ease-in-out infinite; }
@keyframes ss-res-travel {
0%, 30% { right: 0%; opacity: 0; }
33% { opacity: 1; }
48% { right: calc(100% - 13px); opacity: 1; }
51%, 100%{ right: calc(100% - 13px); opacity: 0; }
}
@container sscard (max-width: 620px) {
.infographic-staticsite { aspect-ratio: auto; height: auto; overflow: visible; }
.ss-stage { flex: none; min-height: auto; flex-direction: column; gap: 0.6rem; padding: 0.7rem; }
.ss-middle { width: 100%; max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
.infographic-staticsite *, .infographic-staticsite *::before, .infographic-staticsite *::after {
animation-duration: 0.001ms !important;
}
}
</style>
<div class="ss-stage">
<div class="ss-node visitor">
<div class="ss-node-box">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z"/><path d="M20.054 15.987H3.946"/></svg>
</div>
<div class="ss-node-label">Visitor</div>
<div class="ss-node-tag">Page displayed</div>
</div>
<div class="ss-middle">
<div class="ss-lane request">
<div class="ss-lane-label">Visits site</div>
<div class="ss-track request"><div class="ss-dot"></div></div>
</div>
<div class="ss-lane response">
<div class="ss-lane-label">Sends the files as-is</div>
<div class="ss-track response">
<div class="ss-chip"></div>
<div class="ss-chip"></div>
<div class="ss-chip"></div>
<div class="ss-chip"></div>
</div>
</div>
</div>
<div class="ss-node server">
<div class="ss-node-box" style="border-radius:16px; width:auto; height:auto; padding:clamp(0.4rem,1.6cqw,0.7rem); background:var(--paper);">
<div class="ss-shelf">
<div class="ss-shelf-item"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/><rect width="7" height="7" x="14" y="14" rx="1"/></svg><div class="ss-shelf-check">✓</div></div>
<div class="ss-shelf-item"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m14.622 17.897-10.68-2.913"/><path d="M18.376 2.622a1 1 0 1 1 3.002 3.002L17.36 9.643a.5.5 0 0 0 0 .707l.944.944a2.41 2.41 0 0 1 0 3.408l-.944.944a.5.5 0 0 1-.707 0L8.354 7.348a.5.5 0 0 1 0-.707l.944-.944a2.41 2.41 0 0 1 3.408 0l.944.944a.5.5 0 0 0 .707 0z"/><path d="M9 8c-1.804 2.71-3.97 3.46-6.583 3.948a.507.507 0 0 0-.302.819l7.32 8.883a1 1 0 0 0 1.185.204C12.735 20.405 16 16.792 16 15"/></svg><div class="ss-shelf-check">✓</div></div>
<div class="ss-shelf-item"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m18 16 4-4-4-4"/><path d="m6 8-4 4 4 4"/><path d="m14.5 4-5 16"/></svg><div class="ss-shelf-check">✓</div></div>
<div class="ss-shelf-item"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg><div class="ss-shelf-check">✓</div></div>
<div class="ss-shelf-item"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4v16"/><path d="M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2"/><path d="M9 20h6"/></svg><div class="ss-shelf-check">✓</div></div>
<div class="ss-shelf-item"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5"/><rect x="2" y="6" width="14" height="12" rx="2"/></svg><div class="ss-shelf-check">✓</div></div>
</div>
</div>
<div class="ss-node-label">Server</div>
<div class="ss-nologic">
<div class="ss-nologic-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 10.27 7 3.34"/><path d="m11 13.73-4 6.93"/><path d="M12 22v-2"/><path d="M12 2v2"/><path d="M14 12h8"/><path d="m17 20.66-1-1.73"/><path d="m17 3.34-1 1.73"/><path d="M2 12h2"/><path d="m20.66 17-1.73-1"/><path d="m20.66 7-1.73 1"/><path d="m3.34 17 1.73-1"/><path d="m3.34 7 1.73 1"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="12" r="8"/></svg></div>
<div class="ss-nologic-text">No logic runs</div>
</div>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-staticsite')
|| document.querySelector('.infographic-staticsite');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
</script>π All files (HTML, CSS, JS, images, fonts, videos) are created ahead of time and uploaded to a server.
π¨ When a user visits, the server just sends the stored files β no logic runs, nothing changes.
Flow: Developer creates files β uploads to server β user requests page β server sends the same files β browser displays them as-is.
β¨ Characteristics
β‘ Fast & easy to host
ποΈ No database, no server-side code
π₯ Every visitor sees identical content
π‘ Good for:
π€ Portfolios Β· π Resumes Β· π’ Company pages Β· π Landing pages Β· π Docs
β Isn't a page full of JS animations "dynamic"?
Not in this sense. JS clicking, menus, sliders, and validation are front-end interactivity β they happen inside the browser. "Dynamic" here specifically means the server rebuilds the page per request. A JS-heavy page can still be a static website if the files never change on the server.
βοΈ Dynamic Websites (Server-Side Rendering)
π The server generates the HTML fresh for every request instead of serving fixed files.
βοΈ It runs app code, ποΈ reads the database, ποΈ builds the page, then sends it to the browser.
Components: Browser β HTTP Server β Node.js App β Database
<!-- Infographic: Client/Server request-response with a worked example (amazon.com) β 16:9, responsive, synced timeline -->
<div class="infographic-csexample">
<style>
.infographic-csexample {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
width: 100%;
max-width: 1000px;
margin: 0 auto;
box-sizing: border-box;
aspect-ratio: 16 / 9;
display: flex;
flex-direction: column;
container-type: inline-size;
container-name: cscard;
}
.infographic-csexample[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-csexample * { box-sizing: border-box; }
.cx-stage {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: clamp(0.3rem, 2.5cqw, 1.2rem);
min-height: 0;
min-width: 0;
padding: clamp(0.5rem, 3cqw, 1.5rem);
}
/* --- endpoint nodes --- */
.cx-node {
display: flex;
flex-direction: column;
align-items: center;
gap: clamp(0.2rem, 1cqw, 0.45rem);
flex: 0 0 auto;
min-width: 0;
}
.cx-node-box {
width: clamp(52px, 15cqw, 118px);
height: clamp(52px, 15cqw, 118px);
border-radius: 50%;
border: 2px solid var(--line);
background: var(--paper-alt);
display: flex;
align-items: center;
justify-content: center;
color: var(--accent);
position: relative;
flex: 0 0 auto;
}
.cx-node-box svg { width: clamp(22px, 6.2cqw, 46px); height: clamp(22px, 6.2cqw, 46px); stroke: var(--accent); }
.cx-node-label { font-size: clamp(0.42rem, 1.7cqw, 0.84rem); font-weight: 700; white-space: nowrap; }
.cx-node-sub { font-size: clamp(0.3rem, 1.1cqw, 0.56rem); color: var(--ink-soft); white-space: nowrap; text-align: center; }
.cx-node-tag {
font-size: clamp(0.32rem, 1.2cqw, 0.62rem);
font-weight: 700;
color: var(--accent);
opacity: 0;
white-space: nowrap;
}
/* server: pulses + "Processing" tag right as the request arrives (~14%) */
.cx-node.server .cx-node-box::before {
content: "";
position: absolute; inset: -6px;
border-radius: 50%;
border: 1.5px dashed var(--accent);
opacity: 0;
animation: cx-server-ring 6s ease-out infinite;
}
@keyframes cx-server-ring {
0%, 10% { opacity: 0; transform: scale(0.9); }
14% { opacity: 0.6; transform: scale(0.96); }
36% { opacity: 0.25; transform: scale(1.05); }
40% { opacity: 0; transform: scale(1.14); }
100% { opacity: 0; }
}
.cx-node.server .cx-node-tag { animation: cx-server-tag 6s ease-in-out infinite; }
@keyframes cx-server-tag {
0%, 12% { opacity: 0; }
16%, 38% { opacity: 1; }
42%, 100%{ opacity: 0; }
}
/* browser: bounces + "Rendered" tag once the response arrives (~58%) */
.cx-node.browser .cx-node-box {
animation: cx-browser-pop 6s cubic-bezier(.34,1.56,.64,1) infinite;
}
@keyframes cx-browser-pop {
0%, 56% { transform: scale(1); border-color: var(--line); background: var(--paper-alt); }
60% { transform: scale(1.18); border-color: var(--accent); background: var(--accent-soft); }
66% { transform: scale(1.04); border-color: var(--accent); background: var(--accent-soft); }
90% { transform: scale(1.04); border-color: var(--accent); background: var(--accent-soft); }
96%, 100% { transform: scale(1); border-color: var(--line); background: var(--paper-alt); }
}
.cx-node.browser .cx-node-tag { animation: cx-browser-tag 6s ease-in-out infinite; }
@keyframes cx-browser-tag {
0%, 58% { opacity: 0; }
62%, 90% { opacity: 1; }
95%, 100%{ opacity: 0; }
}
/* --- middle: request lane (top) + response lane (bottom) --- */
.cx-middle {
flex: 1 1 auto;
min-width: clamp(120px, 26cqw, 320px);
max-width: 360px;
display: flex;
flex-direction: column;
gap: clamp(0.7rem, 3.5cqw, 1.4rem);
}
.cx-lane { position: relative; display: flex; flex-direction: column; align-items: center; gap: clamp(0.12rem, 0.7cqw, 0.3rem); }
.cx-lane-label {
font-size: clamp(0.32rem, 1.3cqw, 0.62rem);
font-weight: 700;
letter-spacing: 0.02em;
color: var(--ink-soft);
white-space: nowrap;
opacity: 0;
}
.cx-lane.request .cx-lane-label { animation: cx-req-label 6s ease-in-out infinite; }
@keyframes cx-req-label { 0%,2%{opacity:0;} 5%,32%{opacity:1;} 38%,100%{opacity:0;} }
.cx-lane.response .cx-lane-label { animation: cx-res-label 6s ease-in-out infinite; }
@keyframes cx-res-label { 0%,41%{opacity:0;} 44%,68%{opacity:1;} 74%,100%{opacity:0;} }
.cx-track { position: relative; width: 100%; height: 2px; background: var(--line); }
.cx-track.request::after {
content: ""; position: absolute; right: -1px; top: 50%;
width: clamp(5px, 1.3cqw, 8px); height: clamp(5px, 1.3cqw, 8px);
border-top: 2px solid var(--line); border-right: 2px solid var(--line);
transform: translateY(-50%) rotate(45deg);
}
.cx-track.response::before {
content: ""; position: absolute; left: -1px; top: 50%;
width: clamp(5px, 1.3cqw, 8px); height: clamp(5px, 1.3cqw, 8px);
border-bottom: 2px solid var(--line); border-left: 2px solid var(--line);
transform: translateY(-50%) rotate(45deg);
}
.cx-dot {
position: absolute; top: 50%;
width: clamp(5px, 1.4cqw, 8px); height: clamp(5px, 1.4cqw, 8px);
border-radius: 50%;
background: var(--accent);
transform: translateY(-50%);
}
.cx-track.request .cx-dot { left: 0; animation: cx-req-travel 6s ease-in-out infinite; }
@keyframes cx-req-travel {
0%, 2% { left: 0%; opacity: 0; }
5% { opacity: 1; }
12% { left: calc(100% - 8px); opacity: 1; }
15%, 100%{ left: calc(100% - 8px); opacity: 0; }
}
/* response: 4 small content chips (HTML/CSS/JS/Data) travel back together, staggered */
.cx-chip {
position: absolute; top: 50%; right: 0;
width: clamp(9px, 2.4cqw, 15px); height: clamp(9px, 2.4cqw, 15px);
border-radius: 4px;
background: var(--accent);
color: #fff;
font-size: clamp(4.5px, 1.4cqw, 7.5px);
font-weight: 800;
display: flex; align-items: center; justify-content: center;
transform: translateY(-50%);
}
.cx-chip.html { animation: cx-res-travel 6s ease-in-out infinite; animation-delay: 0s; }
.cx-chip.css { animation: cx-res-travel 6s ease-in-out infinite; animation-delay: 0.15s; }
.cx-chip.js { animation: cx-res-travel 6s ease-in-out infinite; animation-delay: 0.3s; }
.cx-chip.data { animation: cx-res-travel 6s ease-in-out infinite; animation-delay: 0.45s; }
@keyframes cx-res-travel {
0%, 43% { right: 0%; opacity: 0; }
46% { opacity: 1; }
56% { right: calc(100% - 15px); opacity: 1; }
59%, 100%{ right: calc(100% - 15px); opacity: 0; }
}
@container cscard (max-width: 560px) {
.infographic-csexample { aspect-ratio: auto; height: auto; overflow: visible; }
.cx-stage { flex: none; min-height: auto; flex-direction: column; gap: 0.6rem; padding: 0.7rem; }
.cx-middle { width: 100%; max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
.infographic-csexample *, .infographic-csexample *::before, .infographic-csexample *::after {
animation-duration: 0.001ms !important;
}
}
</style>
<div class="cx-stage">
<div class="cx-node browser">
<div class="cx-node-box">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z"/><path d="M20.054 15.987H3.946"/></svg>
</div>
<div class="cx-node-label">Browser</div>
<div class="cx-node-sub">Chrome · Firefox · Edge · Safari</div>
<div class="cx-node-tag">Renders page</div>
</div>
<div class="cx-middle">
<div class="cx-lane request">
<div class="cx-lane-label">GET www.amazon.com</div>
<div class="cx-track request"><div class="cx-dot"></div></div>
</div>
<div class="cx-lane response">
<div class="cx-lane-label">HTML · CSS · JS · Data</div>
<div class="cx-track response">
<div class="cx-chip html">H</div>
<div class="cx-chip css">C</div>
<div class="cx-chip js">J</div>
<div class="cx-chip data">D</div>
</div>
</div>
</div>
<div class="cx-node server">
<div class="cx-node-box">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"/><rect width="20" height="8" x="2" y="14" rx="2" ry="2"/><line x1="6" x2="6.01" y1="6" y2="6"/><line x1="6" x2="6.01" y1="18" y2="18"/></svg>
</div>
<div class="cx-node-label">Server</div>
<div class="cx-node-sub">Amazon's server</div>
<div class="cx-node-tag">Processing</div>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-csexample')
|| document.querySelector('.infographic-csexample');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
})();
</script>Flow:
π€ User requests
example.com/profileπ¨ HTTP server receives it, passes it to the Node.js app
π§ App figures out what data is needed
ποΈ Fetches it from the database (user info, posts, orders, etc.)
ποΈ Combines data + HTML template + CSS/JS into a complete page
π¨ Sends the finished page to the browser
π₯οΈ Browser displays it
Why "dynamic"?
The page changes based on logged-in user, database content, time, or new data β a fresh page every time. Twitter shows different posts today vs. tomorrow because new posts hit the database and the server regenerates the page each visit.
Same idea for "About Us" (identical for everyone) vs. "Welcome Rahul" / "Welcome Abhijit" (changes per user).
ποΈ Building the full page (HTML/CSS/JS) on the server before sending it is called Server-Side Rendering (SSR).
π Quick terminology: a website (blogs, news, docs) is mainly for reading; a web application (Gmail, Amazon, Netflix) lets users perform tasks like login, search, upload, or buy. Dynamic sites often blur into web apps since both rely on server-generated, per-user content.
π API-Powered Websites (Client-Side Rendering)
π¦ Instead of sending a full HTML page, the server sends just data β usually JSON β and the browser builds the page itself.
Components: Browser β API β Node.js β Database
<aside>
π‘
[ infographics ]
</aside>
Flow:
π€ User opens a page
π¨ Browser calls the API, e.g.
GET /api/productsπ’ Node.js fetches data from the database
π¦ Sends back only JSON:
[
{ "name": "Laptop", "price": 50000 },
{ "name": "Mouse", "price": 700 }
]βοΈ JavaScript (or React/Angular/Vue) turns that JSON into HTML
π₯οΈ Browser displays the page
This browser-side page-building is called Client-Side Rendering (CSR) β the mirror image of SSR: instead of the server sending ready HTML, it sends raw JSON data, and the browser does the rendering.
JSON, the format APIs use, is pure data β no HTML, CSS, or layout:
{ "name": "Abhijit", "age": 22, "city": "Durgapur" }π Why APIs Are So Powerful
π An API (Application Programming Interface) lets different apps exchange data instead of full webpages.
π The same API can serve many clients at once β π website, π± mobile app, π» desktop app, β IoT device β with zero duplicated back-end code. One API at
example.com/api/coursescould power a website, an Android app, an iPhone app, and a desktop app simultaneously.β Why not just use SSR everywhere? Because only browsers understand raw HTML. Mobile and desktop apps need structured data, not rendered pages β that's exactly what JSON from an API provides.
πΌ Some companies sell only APIs, not websites, and let others build on top: π³ Stripe (payments) Β· πΊοΈ Google Maps Β· π¦οΈ weather APIs Β· π± currency exchange APIs.
π Full Comparison
Feature | π Static | βοΈ Dynamic (SSR) | π API-Powered (CSR) |
|---|---|---|---|
HTML created | Before deployment | On server, per request | In the browser |
Database | β No | β Yes | β Yes |
Node.js app | β No | β Yes | β Yes |
Content changes | β No | β Yes | β Yes |
Server sends | HTML/CSS/JS | Generated HTML/CSS/JS | JSON only |
Browser builds page | β No | β No | β Yes |
Best for | Portfolios, landing pages | Blogs, dashboards, traditional apps | React/Angular/Vue apps |
π Final Takeaway
π Static β fast, simple, pre-built files
βοΈ Dynamic (SSR) β server builds fresh HTML per request using logic + database
π API-Powered (CSR) β server sends JSON, browser builds the UI
Understanding these three lays the groundwork for Node.js, Express.js, APIs, MongoDB, and frameworks like React, Angular, and Vue. π