the full skeleton
every HTML page, no matter how simple or complex, starts from this same template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>my page</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- everything visible goes here -->
</body>
</html>
breaking it down
<!DOCTYPE html>— tells the browser "this is a modern HTML5 document." always the very first line.<html lang="en">— wraps the whole page. thelangattribute tells browsers and screen readers what language the content is in.<head>— holds information about the page that isn't shown directly on screen: title, character encoding, linked fonts and stylesheets, favicon.<meta charset="UTF-8">— makes sure special characters (like ♡ or accented letters) render correctly instead of turning into garbled symbols.<title>— the text shown in the browser tab.<meta name="viewport" ...>— tells mobile browsers to render the page at the device's actual width instead of zoomed out. skip this and your page will look tiny on phones.<body>— everything the visitor actually sees: text, images, buttons, all of it.
adding fonts and styles
custom fonts (like the ones used across this site) get linked inside <head>, before your own <style> block:
<head>
...
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<style>
body { font-family: 'Nunito', sans-serif; }
</style>
</head>
preconnect link isn't strictly required, but it lets the browser start connecting to google fonts' servers early, so the font loads a little faster.a more complete head
the skeleton above covers the bare minimum. in practice, most real pages — including this one — pack a lot more into <head>: seo hints, social media preview tags, favicons, font connections, and scripts. here's what this exact page's <head> looks like in full:
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>html structure ♡ tutorials</title>
<link rel="shortcut icon" href="https://kkul.store/media/graphics/melodys.gif">
<meta name="robots" content="nosnippet">
<meta name="robots" content="max-snippet:0">
<meta name="robots" content="noarchive">
<meta name="robots" content="notranslate">
<meta name="robots" content="nositelinkssearchbox">
<meta name="robots" content="max-video-preview:0">
<meta name="robots" content="max-image-preview:standard">
<meta name="title" content="tutorials ♡">
<meta name="description" content="made with ribbons & honey">
<meta name="url" content="https://kkul.store/">
<meta name="identifier-URL" content="https://kkul.store/">
<meta name="thumbnail" content="https://kkul.store/media/backgrounds/chii-og.jpg">
<meta property="og:url" content="https://kkul.store/">
<meta property="og:title" content="tutorials ♡">
<meta property="og:site_name" content="https://kkul.store/">
<meta property="og:description" content="made with ribbons & honey">
<meta property="og:type" content="website">
<meta property="og:image" content="https://kkul.store/media/backgrounds/chii-og.jpg">
<meta property="og:image:type" content="image/jpeg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="illustration by _mika_0_0">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="https://kkul.store/">
<meta name="twitter:title" content="tutorials ♡">
<meta name="twitter:description" content="made with ribbons & honey">
<meta name="twitter:image" content="https://kkul.store/media/backgrounds/chii-og.jpg">
<meta name="twitter:image:alt" content="illustration by _mika_0_0">
<meta name="copyright" content="© 2026 kkul.store. all rights reserved.">
<meta name="author" content="mocha">
<link rel="icon" href="/media/graphics/melodys.gif" type="image/gif">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="/styles/tutorial-post.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://static.tumblr.com/lspzyz3/xloqk6cgp/jquery.style-my-tooltips.js"></script>
that's a lot at once, so let's go through it group by group.
meta tags: search engines & robots
these tags don't change how the page looks to a visitor at all — they're instructions aimed at search engine crawlers (google, bing, etc), telling them how to treat and display this page in search results.
<meta name="robots" content="nosnippet">— normally, google shows a short preview of your page's text underneath the title in search results (called a "snippet"). this tag tells google not to generate one at all, so only the title and url show up.content="max-snippet:0"— a more explicit version of the same idea: it caps the snippet length at exactly zero characters, which functions the same asnosnippetbut is the newer, more precise way to write it.content="noarchive"— google normally keeps a saved "cached" copy of your page, viewable even if your site goes down temporarily. this tag disables that cached copy from being offered.content="notranslate"— google sometimes shows a "translate this page" prompt in search results if it detects the content is in a language different from the searcher's. this tag turns that offer off.content="nositelinkssearchbox"— for well-known sites, google sometimes adds a mini search box directly under the main search result, letting people search your site from google itself. this opts out of that feature.content="max-video-preview:0"— if your page has embedded video, google may auto-play a short preview of it right in search results. setting this to0disallows any video preview from being generated.content="max-image-preview:standard"— controls how large an image thumbnail google is allowed to show for this page in results.standardcaps it at a normal size instead of the largest possible ("large") or none at all ("none").
<meta name="robots"> tags like this — they can be combined into a single line by comma-separating the values: <meta name="robots" content="nosnippet, noarchive, notranslate">. writing them out individually (like this page does) works exactly the same, it's just more verbose and easier to toggle one on/off at a time.meta tags: title, description & identity
this group tells search engines (and some browser tools) what the page is fundamentally about.
<meta name="title">— a duplicate of the page's title, stored as metadata rather than in the visible<title>tag. most modern search engines actually ignore this and read the real<title>tag instead, but some older tools and browser extensions still check it, so it's harmless to include as a backup.<meta name="description">— the short one or two sentence summary that search engines display underneath your title in the results list. this is one of the few meta tags that actually affects what a visitor sees before clicking, so it's worth writing something inviting and accurate.<meta name="url">and<meta name="identifier-URL">— both point back to the "real," canonical address of this content. they help tools understand where the authoritative version of the page lives, especially useful if the same content is ever mirrored or accessible from more than one url.
open graph tags (the og: ones)
open graph is a standard originally created by facebook, now used by nearly every platform (discord, tumblr, imessage, whatsapp, slack, and more) to generate the little preview card that appears when someone pastes your link somewhere. without these tags, a shared link just shows a bare, plain-text title and url — no image, no description, nothing eye-catching.
og:url— the canonical link this content officially lives at. platforms use this so the preview card links back to the correct address, even if the link was shared from a slightly different url.og:title— the bold, large text shown at the top of the preview card.og:description— the smaller text shown underneath the title in the card.og:site_name— the site's name, usually shown in small text above or below the title, so people recognize which site the link is from at a glance.og:type— categorizes what kind of content this is. common values arewebsitefor a general page orarticlefor a blog-style post; some platforms use this to slightly change how the card is laid out.og:image— the thumbnail image shown in the preview card. this is usually the single most important open graph tag, since it's what actually catches someone's eye.og:image:type— the mime type of that image file (e.g.image/jpeg,image/png), so the receiving platform knows how to decode it without having to guess.og:image:width/og:image:height— the exact pixel dimensions of the image. providing these lets the platform reserve the right amount of space for the image immediately, instead of waiting for the image to load first to figure out its size (which would otherwise cause the preview card to visibly "jump" as it loads).og:image:alt— alternative text describing the image, read aloud by screen readers for visitors who are visually impaired, and shown as a fallback if the image fails to load.
og:image size is 1200×630 pixels — that's roughly a 1.91:1 ratio, which is what most platforms crop preview images to. using a different ratio risks having the important part of your image cropped out awkwardly on some platforms.twitter card tags
twitter/X reads open graph tags as a fallback, but has its own separate set of tags for finer control over how links look specifically on that platform.
twitter:card— sets the overall layout type of the preview.summary_large_image(used here) shows one large image spanning the full width above the title; the alternative,summary, shows a small square thumbnail beside the text instead.twitter:url,twitter:title,twitter:description,twitter:image— these mirror theirog:counterparts exactly, letting you set twitter-specific text/images if you ever want them to differ from the open graph versions. here they're set to the same content as the og: tags.twitter:image:alt— alt text specifically for the twitter preview image, same purpose asog:image:altbut read by twitter's own accessibility tools.
credits & housekeeping meta tags
<meta name="copyright">— a plain-text copyright notice stored as metadata. browsers don't display or enforce this in any way — it's purely informational, mostly read by archival tools or humans viewing the page source.<meta name="author">— states who made the page. like copyright, this isn't shown anywhere visible and isn't enforced — it's just good practice to credit yourself in the source code.
favicon links
the favicon is the small icon shown in the browser tab, in bookmarks, and in browser history next to the page title.
<link rel="shortcut icon">— the older, legacy way of declaring a favicon, still respected by some older browsers.<link rel="icon">— the modern standard way to declare the same thing, including atypeattribute (here,image/gif) so the browser knows the file format upfront without having to inspect it.
shortcut icon.connecting to external resources early
loading fonts (or any resource) from another domain normally means the browser has to do several separate steps before it can even start downloading the file: look up the domain's address (DNS lookup), open a secure connection to it (TLS handshake), and then finally request the file. each of these steps takes a small amount of time, and normally they only start once the browser reaches the actual <link> or <script> tag that needs the resource.
<link rel="preconnect" href="https://fonts.googleapis.com">— tells the browser to get a head start on connecting to google fonts' main server, before it's actually needed. this is where the font's css file (which lists what font files to download) is hosted.<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>— the actual font files themselves (the .woff2 files with the letter shapes) are served from this second, different domain, so it needs its own separate preconnect. thecrossoriginattribute is required here because fonts are fetched with what's called "anonymous mode" cross-origin requests — without it, the browser would open a second, wasted connection instead of reusing this preconnected one.<link rel="stylesheet" href="/styles/tutorial-post.css">— this is a normal stylesheet link (no preconnect needed, since it's on the same domain as the page itself), loading the css specific to this tutorial page's layout.
loading scripts in the head
by default, when a browser reaches a <script> tag, it stops building the rest of the page, downloads the script fully, runs it top to bottom, and only then continues. placing scripts in <head> means this pause happens before the visitor sees anything at all, since <head> is parsed before <body>.
jquery-3.6.0.min.js— loads the jquery library itself, a toolkit that simplifies common javascript tasks like selecting elements and handling events. many older plugins (including the one below) are built expecting jquery to already exist.jquery.style-my-tooltips.js— a plugin that adds styled, customizable tooltips, built directly on top of jquery's features. because it depends on jquery already being loaded and ready, its<script>tag has to come after jquery's tag in the document — script tags run strictly in the order they appear, so reversing these two would cause the tooltip plugin to fail immediately, since it would be looking for jquery before jquery exists yet.
<head> with no special attributes, is sometimes called "render-blocking" — it can slightly delay the page from appearing, since the browser is busy downloading and running these scripts before it moves on to building the visible page. for scripts that aren't needed immediately, a common alternative is placing them right before the closing </body> tag instead, so the rest of the page loads first. but when a plugin strictly depends on load order (like the tooltip script here depending on jquery), keeping both together in <head>, in the correct order, is the simplest way to guarantee they work.a note on structure vs. style
HTML's only job is to describe what something is — a heading, a paragraph, a link, an image. it shouldn't be responsible for how it looks. that's what CSS is for. keep them separate and your pages stay easy to maintain.