Yes, you must copy and paste content and not having layout page is annoying at times. But the overhead of just doing it yourself is surprisingly small in terms of the time commitment.
Typically, I'll draft a post in MS Word then open the git repo for my site, hosted on github pages, duplicate and rename the template.html page that includes the CSS, footer, and header for my site and then copy my content into it. When I'm happy with everything, I'll make my commit and then a minute later it's live at my custom domain. Seeing that it takes only 11KBs and 26ms to load my landing page strangely delightful.
HTML was envisioned as an SGML application/vocabulary, and SGML has those power features, such as type-checked shared fragments/text macros (entities, possibly with parameters), safe third-party content transclusion, markup stream processing and filtering for generating a table of content for page or site navigation, content screening for removal/rejection of undesired script in user content, expansion of custom Wiki syntax such as markdown into HTML, producing "views" for RSS or search result pages in pipelines, etc. etc. See [1] for a basic tutorial.
[1]: https://sgmljs.net/docs/producing-html-tutorial/producing-ht...
Same here. I believed that SGML was like Lisp of markup languages, except that it went completely extinct. Good to see it's still usable, I feel like I want to try it out now (instead of making a third generation of my static site generator from scratch).
Any type-checking inside of SGML is more akin to unused-variable checking. When you say that macros/entities may contain parameters, I think you are referring to recursive entity expansion, which does let you parameterize macros (but only once, and not dynamically within the text). For instance, you can set a `¤tYear` entity and refer to that in `copywrite "¤tYear/¤tDay`, but that can only happen in the DTD at the start of the document. It’s not the case that you could, for instance, create an entity to generate a Github repo link and use it like `&repoName = "diff-match-patch"; &githubLink`. This feature was used in limited form to conditionally include sections of markup since SGML contains an `IGNORE` “marked section”.
<!ENTITY % private-render "IGNORE">
...
<![%private-render[
<side-note>
I’m on the fence about including this bit.
It’s not up to the editorial standards.
</side-note>
]]>
SGML also fights hard against stream processing, even more so than XML (and XML pundits regret not deprecating certain SGML features like entities which obstruct stream processing). Because of things like this, it’s not possible to parse a document without having the entire thing from the start, and because of things like tag omission (which is part of its syntax “MINIMIZATION” features), it’s often not possible to parse a document without having _everything up to the end_.Would love to hear what you are referring to with “safe” third-party transclusion and also what features are available for removal or rejection of undesired script in user content.
Apart from these I find it a pleasure to use because SGML makes it easy for _humans_ to write structured content (contrast with XML which makes it easy for software to parse). SGML is incredibly hard to parse because in order to accommodate human factors _and actually get people to write structured content_ it leans heavily on computers and software doing the hard work of parsing.
It’s missing some nice features such as namespacing. That is, it’s not possible to have two elements of the same name in the same document with different attributes, content, or meanings. If you want to have a flight record and also a list of beers in a flight, they have to be differentiated otherwise they will fail to parse.
<flight-list>
<flight-record><flight-meta pnr=XYZ123 AAL number=123>
</flight-list>
<beer-list>
<beer-flight>
<beer Pilsner amount=3oz>Ultra Pils 2023
<beer IPA>Dual IPA
<beer Porter>Chocolate milk stout
</beer-list>
DSSSL was supposed to be the transforms into RSS, page views, and other styles or visualizations. With XML arose XSL/XSLT which seemed to gain much more traction than DSSSL ever did. My impression is that declarative transforms are best suited for simpler transforms, particularly those without complicated processing or rearranging of content. Since `osgmls` and the other few SGML parsers are happy to produce an equivalent XML document for the SGML input, it’s easy to transform an SGML document using XSL, and I do this in combination with a `Makefile` to create my own HTML pages (fair warning: HTML _is not XML_ and there are pitfalls in attempting to produce HTML from an XML tool like XSL).For more complicated work I make quick transformers with WordPress’ HTML API to process the XML output (I know, XML also isn’t HTML, but it parses reliably for me since I don’t produce anything that an HTML parser couldn’t parse). Having an imperative-style processor feels more natural to me, and one written in a programming language that lets me use normal programming conveniences. I think getting the transformer right was never fully realized with the declarative languages, which are similar to Angular and other systems with complicated DSLs inside string attribute values.
I’d love to see the web pick up where SGML left off and get rid of some of the legacy concessions (SGML was written before UTF-8 and its flexibility with input encodings shows it — not in a good way either) as well as adopt some modern enhancements. I wrote about some of this on my personal blog, sorry for the plug.
https://fluffyandflakey.blog/2024/10/11/ugml-a-proposal-to-u...
Edit: formatting
> When you say that macros/entities may contain parameters, I think you are referring to recursive entity expansion,
No, I'm referring to SGML data attributes (attributes declared on notations having concrete values defined on entities of the respective notation); cf. [1]. In sgmljs.net SGML, these can be used for SGML templating which is a way of using data entities declared as having the SGML notation (ie. stand-alone SGML files or streams) to replace elements in documents referencing those entities. Unlike general entities, this type of entity expansion is bound to an element name and is informed of the expected content model and other contextual type info at the replacement site, hence is type-safe. Data attributes supplied at the expansion site appear as "system-specific entities" in the processing context of the template entity. See [2] for details and examples.
Understanding and appreciating the construction of templating as a parametric macro expansion mechanism without additional syntax may require intimate knowledge of lesser known SGML features such as LPDs and data entities, and also some HyTime concepts.
> create an entity to generate a Github repo link
Templating can turn text data from a calling document into an entity in the called template sub-processing context so might help with your use case, and with the limitation to have to declare things in DTDs upfront in general.
> it’s not possible to parse a document without having the entire thing from the start, and because of things like tag omission (which is part of its syntax “MINIMIZATION” features), it’s often not possible to parse a document without having _everything up to the end_.
Why do you think so and why should this be required by tag inference specifically? In sgmljs.net SGML, for external general entities (unlike external parameter entities which are expanded at the point of declaration rather than usage), at no point does text data have to be materialised in its entirety. The parser front-end just switches input events from another external source during entity expansion and switches back afterwards, maintaining a stack of open entities.
Regarding namespaces, one of their creators (SGML demi-good James Clark himself) considers those a failure:
> the pain that is caused by XML Namespaces seems massively out of proportion to the benefits that they provide (cf. [3]).
In sgmljs.net SGML, you can handle XML namespace mappings using the special processing instructions defined by ISO/IEC 19757-9:2008. In effect, element and attributes having names "with colons" are remapped to names with canonical namespace parts (SGML names can allow colons as part of names), which seems like the sane way to deal with "namespaces".
I haven't checked your site, but most certainly will! Let's keep in touch; you might also be interested in sgmljs.net SGML and the SGML DTD for modern HTML at [4], to be updated for WHATWG HTML review draft January 2025 when/if it's published.
Edit:
> Would love to hear what you are referring to with “safe” third-party transclusion and also what features are available for removal or rejection of undesired script in user content.
In short, I was mainly referring to DTD techniques (content models, attribute defaults) here.
[1]: https://sgmljs.net/docs/sgmlrefman.html#data-entities
[2]: https://sgmljs.net/docs/templating.html
This calls out for server side includes[0]. I so loved server side includes back in the late 90s. You still work in plain HTML and CSS, boilerplate can be centralized and not repeated, and clients receive the entire page in a single request.
Holy cow. The sole reason I learned SSI and then PHP in 1998 was because I was sick of this after like 2 weeks.
This person has more patience in their pinky than I have ever had.
Many people who maintain their own sites in vanilla web technologies tend to create reusable functions to handle this for them. It can generate headers and the like dynamically so you don't have to change it on every single page. Though that does kill the "no javascript required" aspect a lot of people like
Of course you could simply add a build step to your pure HTML site instead!
<object data="footer.html"></object>
Turn your back for twenty-five years, and be amazed at what they've come up with! ;-)Should reduce a lot of boilerplate that would get out of sync on my next project, without need for templating.
- HTTP/1.1 (1997) already reuses connections, so it will not double latency. The DNS lookup and the TCP connection are a high fixed cost for the first .html request.
- HTTP/2 (2015) further reduces the cost of subsequent requests, with a bunch of techniques, like dictionary compression.
- You will likely still be 10x faster than a typical "modern" page with JavaScript, which has to load the JS first, and then execute it. The tradeoff has flipped now, where execution latency for JS / DOM reflows can be higher than network latency. So using raw HTML means you are already far ahead of the pack.
So say you have a 50 ms time for the initial .html request. Then adding some <object> might bring you to 55 ms, 60 ms, 80 ms, 100 ms.
But you would have to do something pretty bad to get to 300 ms or 1500 ms, which you can easily see on the modern web.
So yes go ahead and add those <object> tags, if it means you can get by with no toolchain. Personally I use Markdown and some custom Python scripts to generate the header and footer.
> be cached for subsequent access.
So now you need to setup cache control?
The only reason I use a blog engine now (Hugo) is for RSS. I kept messing up or forgetting manual RSS edits.
It also has the benefit of forcing you to keep your URIs stable. Cool URIs don't change: https://www.w3.org/Provider/Style/URI.html
Yeah, I noped out of that and use a client-side include (webcomponent) so that my html can have `<include-remote remote-src='....'>` instead.
Sure, it requires JS to be enabled for the webcomponent to work, but I'm fine with that.
See https://www.lelanthran.com for an example.
[EDIT: Dammit, my blog doesn't use that webcomponent anymore! Here's an actual production usage of it: https://demo.skillful-training.com/project/webroot/ (use usernames (one..ten)@example.com and password '1' if you want to see more usage of it)]
I doubt your blog would last a single month without some breaking change of some sort in one of the packages.
Every upgrade in the JS world is very painful.
Edit: Oh right, OS upgrades could do it. Or network keys changing etc...
Perfect example. HN will see a page with 6Mb of images/video, 1Mb of CSS and 200Kb of JavaScript and say "look at how much the JavaScript is bloating that page".
Nah, it's the opposite. JS tends to perform better and be more usable for the same level of feature complexity (people who want more complex sites, for good reasons or bad, tend to use JS, but if you compare like with like), HN just likes to use them as a stick to reinforce their prejudices. (E.g. if you actually test with a screenreader, aria labels work better than "semantic" HTML tags)
Interesting how this is opposite to the recommendations from MDN, such as:
Warning: Many of these widgets are fully supported in modern browsers. Developers should prefer using the correct semantic HTML element over using ARIA, if such an element exists.
The first rule of ARIA use is "If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so." -- which also refers to: https://www.w3.org/TR/using-aria/#rule1
Though I can believe that real life may play out different than recommendations.
Also, as I understand it, ARIA is orthogonal to JS, and it doesn't alter behavior for browser users.
I think this was one of the most common usages of PHP in the beginning, at least for those who basically wrote static HTML/CSS and needed a header/footer. It was probably a gateway into more advanced dynamic pages, eventually ending up using databases and other advanced functionality.
<?php include('header.inc'); ?>
<p>Here's a list of my favourite movies</p>
<ul>
<li>...</li>
</ul>
<?php include('footer.inc'); ?>
It would be great if HTML had a similar capability. People have asked for it for over 30 years, so it's unlikely that it will be implemented now.> I think this was one of the most common usages of PHP in the beginning,
> <?php include('header.inc'); ?>
And other tools beforehand: basic CGI or even more basic server-side includes (https://en.wikipedia.org/wiki/Server_Side_Includes)
To reduce CPU and IO load on the server (or just in circumstances where SSI was not enabled on the server they had available) some would pre-process the SSI directives (obviously this doesn't work for dynamic results such as the output from many #exec examples), so all that is being served is simple static files ‑ a precursor to more complex modern static site builders.
> It would be great if HTML had a similar capability. People have asked for it for over 30 years, so it's unlikely that it will be implemented now.
That doesn't really fit with the intentions of HTML, and could impose a bunch of extra network latency overhead compared to using SSI instead, leading to either complete rendering delays or jumpy pages as included content is merged in in steps, though I have seen it implemented multiple ways using a bit of JS (some significantly more janky than others).
Manual work is almost never a good solution. Try this:
for PAGE in *.page
do
cat header.html "$PAGE" footer.html > “$PAGE.html”
done
for PAGE in *.page
do
cat header.html "$PAGE" footer.html > "$PAGE.html"
done
As noted in a peer comment, the cat[0] command supports concatenating multiple files to stdout in one invocation.HTH
EDIT: if you don't want the output file to be named "a.page.html" and instead it to be "a.html", replace the above cat invocation with:
cat header.html "$PAGE" footer.html > "${PAGE%.page}.html"
This syntax assumes use of a POSIX/bash/zsh shell.0 - https://man.freebsd.org/cgi/man.cgi?query=cat&apropos=0&sekt...
<!--# set var="pagetitle" value="Main page" -->
<!--# include file="00__header.html" -->
... main content here
<!--# include file="00__footer.html" -->
I tried things like bashblog for awhile, but it has some quirks like sometimes placing posts out of order when building the index page. That and I have zero use for the built in analytics options or things like Discus comments, so it seemed like I was really only using about 30% of what it was meant to do.
Here's a link to that for anyone interested. It's quite tweakable.
I've started the Slab templating language[0] to be able to define reusable HTML fragments. It means using a dedicated tool but hopefully not needing to resort to a real programming language.
Sorry, pet peeve of mine as a hobby baker.
title
subtitle
.. [two blank lines make a section break]
ingredients with 4 columns, last one is an optional comment for the row
..
method steps with 2 columns, last one is optional comment
..
then optional sections that just have to have:
section title (this is the collapsed title string too)
any rows included until the next .. etc. etc.
plus just a few tricks like if an ingredient comment has [] then it uses that as a URL for the ingredient, if a row in ingredients has just one column then it's a header etc.
Also most of the complexity disappears if you aren't trying to make a blog. They generally all have "simple pages" support that is much simpler than trying to figure out their blog mechanics.
Of course the hard part is picking an SSG you like, and it is easier to just build your own which is a big part of why SSG proliferation happens. Too many options? Make a new one.
My main sites are still in Jekyll for now, for historic reasons of GitHub Pages support.
My latest discovery and new love in this space is Lume [0]. It's definitely on the simpler side of the scale. I haven't tried it for a full blog yet, but the simple website I have built with it has indeed continued to feel simple throughout the process and even using some of the features Lume's documentation labels "Advanced".
Looks around sheepishly
I've been doing that for years and really happy with the result.
Jekyll also has a higher ceiling than Pandoc when you need a templating language, plugins, etc.
I'm currently using Nikola and have done quite a bit of customization - by hacking around and learning modern web stuff as I go (the last time I did this stuff seriously, jQuery was dominant and Bootstrap was brand new - of course I'm not writing a bunch of JavaScript for a blog, but that also presumably dates my understanding of HTML and CSS). I've found that even though there's way more stuff in here than I really want, it's really nice to have that kind of scaffolding to start, and I can strip it away as I customize.
I didn't like how complex that stuff is with Nikola - I didn't have an obvious entry point for making the kinds of customizations I really wanted, and yet there was still so much to look at in order to understand the system. But at the same time I really didn't want to spend hours re-learning CSS more or less from scratch, when I could actually use the examples already in the existing themes.
I did something really awful: instead of trying to make yet another layer of theme "extension", I copied everything locally and have been condensing it as I go.
This had the benefit that I didn't have to decide on a bunch of CSS classes up front in order to have anything look passable. There may be tons of unused stuff, but I'm cleaning that up as I implement my own things - and bit by bit, I get something smaller and more comprehensible that fits my mental models. This conversion process might not be any faster, but I'm certainly enjoying myself more.
At some point in the future I'm considering doing a simple templating engine and converting these templates (originally Mako) to it. It just irritates me that I still have to deal with close tags - both in HTML and in template directives - when I'm doing everything in Python. I have a vague memory of a 2010-era JavaScript templating system - I think it was called Express or something like that? - which used indent-based syntax without closing tags. So I'm inspired by my recollection of that.
That's 4 stacks over the course of 5-6 years. Not worth it.
Decided to do the sensible thing and use GitHub's README functionality. I prefer this approach and wish more folks in the tech community adopted it: https://github.com/SuboptimalEng
The UI is often tangential to the heavy lifting done by the back end. It often needs to be "just good enough".
How can UI be stable if you’re the one changing it all the time even if all you need is a readme page that can be done in the same UI with no change for decades?
A few million people are holding their breath - unlike in the case of my self-hosted site where I am alone to bring it back online.
It's served using his own HTTP server - publicfile, and the DNS domain is served using his own DNS server - djbdns. E-mail is handled using his own SMTP server - qmail. He invented the Maildir e-mail format, de facto standard in all e-mail products. All e-mail mailing lists for his products are handled by his own mailing list server - ezmlm. All of this is managed using his replacements to /etc/rc or /etc/init.d or systemd - daemontools.
He invented ChaCha and Salsa stream ciphers, now in widespread use, as well as elliptic curves, especially the famous Curve25519, and the Poly1305 MAC.
He also invented TCP SYN cookies.
Pretty impressive, no?
I've been writing a progressive web app that is, itself, a "web component" (custom element), built entirely with custom elements, so I feel like I've got a pretty good idea of how you can tackle that header reuse bullet point. Happy to give pointers if you're interested in that at all.
Anyway, great job on simplifying things! I hope it gets easier from here!
I love that you can even drop in Svelte and React blocks right next to each other, so you basically the power of all the advanced frameworks, and the choice to pare it down to a barebones html static site
If you don't want js on the frontend you can just use it as a nice html templating engine. It also renders markdown automatically for you as it recognizes different formats by the file extension.
[1]: https://github.com/withastro/astro/tree/main/examples/minima...
https://www.planetjones.net/blog/03-05-2023/relaunching-my-p...
https://john-doe.neocities.org/
I am not html expert, so I have no idea how complicate or what implications would that have.
section {display:none}
section:target {display:block}
So they use the target selector which becomes active when #pageid is in the url.
But the html for all the pages is outputted, so this won't scale with a big blog.
I wonder how SEO is for this, and if there's a way to make this better with something like the <object> element.I would also make it so the url was example.com/#/pageid, so the id is "/pageid". Looks a bit better I think.
I was thinking in using it for a blog, but I am afraid of having everything in a single file, and that making some mistake will render the whole site useless.
Also not sure how hard would be to manage once it starts to grow... Maybe it needs to grow significantly more than I can before this is a road block.
If you don't want to use a static site generator I think you're better off with just html files for each page/blog entry, or you could use something like htmx and load stuff in that way.
Pro-tips: switch styles to show all content (and buttons) then use contenteditable - for the whole page or allow it at element levels, allow copying/removing specific element ("template"), POST new version, HTTP Authenticated, to the server or just save :)
When I redid my ancient personal site—started in the late 1990s—to make it mobile-friendly a few years ago, BBEdit was also useful when making changes across dozens of files at once.
I still wanted the ability to have a common headers and footers and unique sections without repeating myself in every file. So I created a very small PHP application (just 5 files) and each page or blog post is a single PHP file in a directory. These PHP files have a small bit of metadata code at the top but are otherwise just plain HTML files. In each directory is layout file that wraps the content and these nest up the directory structure. So my site has a common header and footer and each section has their own subheader.
With the ability to publish by git push to the server, writing a blog post is as easy as creating a new file, git commit, and git push.
I wrote about it when I moved from WordPress to Jekyll. https://brajeshwar.com/2021/brajeshwar.com-2021/
You create a common template type with methods like:
LayoutHtml(Session? Session, string title, string innerHtml, ...) => $@"
<html>
(common elements)
{innerHtml}
(common elements)
</html>";
Which is then fed html partial snippets generated however you see fit. The use of methods to abstract partials in a hierarchical fashion like this can manage complex layouts well. You can recurse and compose this structure as much as needed (i.e., partials inside partials).To solve that and other issues, like adding an rss feed and letting pages specify their own publish date, I did what anyone would do: write a custom web server. It's up at https://github.com/playtechnique/andrew/, if anyone wants to give it a whirl.
A little project like mine isn't the right answer for everyone; right now its only user is me. How it solves the problem fits my own little brain : )
I know people will say for the learning experience but learning what? How to basically "hello, world" in sveltekit?
sveltekit is basically html + css in a .svelte file if you don't use javascript.
Was kinda surprised at how many senior leetcode blackbelts didn't know HTML had built in validation :)
JS was required for some of the more complex validation logic and mounting few dom nodes (and again, surprisingly, many didn't know how to create an element and mount it!).
On the other hand I got to learn lots of nice tricks to complete some of the features (elements had to appear with conditional logic) with CSS only which was nice.
Judging by the websites I've had to deal with in the last few years, a lot of web devs don't know that HTML has built in form submission. Or that it's possible to, say, display images without JavaScript (looking squarely at you, Imgur).
- have HTML files for the individual pages/posts (I like the freedom that custom HTML provides)
- have a script file consisting just of a single array of meta data blocks for the individual posts (headline, description, preview image(s), date, tags, additional assets to load, like additional CSS or JS, if required, restricted visibility, etc. – most of this is optional) and content for the preview
- a server-side template script that generates the chrome around an individual page view and a paginated list view from the feed data (this allows for things like pagination, cross-links, filters per tag, we can generate multiple views), and we can also generate a RRS feed from the feed-index. Moreover, as there is also no external input other than fragments from the request URI, which can be laundered easily (e.g., by discarding all non alpha-numeric characters) and checked for resolving to existing file paths in given constraints, this should be also considerably secure. (This is actually a rather short script.)
- a server config (`.htaccess` or similar) that parses parts of the request URL to parameters to be used by the template script.
(So, adding a post is as simple as adding a new HTML file, copying an entry in the feed file and modifying it accordingly for the new page. And it can be done all in a text editor. The only thing missing may be a full-text search, as there is no DB involved and no representation of the content as normalized plain text. On the other hand, this also keeps the server load low.)
1) You can use watchexec https://watchexec.github.io/ to live reload during development. 2) Also, please add a clickable image preview (you can use this lib for example https://github.com/francoischalifour/medium-zoom) 3) No commenting feature, luckily I found your post here on HN. But it would be better to have comment blocks, like from https://giscus.app/ or just a link where readers can comment. 4) No RSS feed. I'd like to subscribe to your updates, but there is no such option right now. RSS is one of the points why site generators are used for static blogs (e.g. Hugo, Zola, Astro, etc.)
If you know Python well enough, my recommendation is Pelican.[1] You can author your posts in Markdown. You specify the desired HTML/CSS. It will then do all the boring work for you. Then just upload the static files to a webserver.
You can do away with the JS with something like Pandoc Highlight Filter: https://gitlab.com/danbarry16/pandoc-highlight-filter
Just take the Python file, make it executable and add it to the filter arguments. It's very basic, but all done during build time. It was originally started to build out HTML documentation for a system that was very particular about what types of files could be used.
It can also do other stuff like build your site with Python blocks that are run: https://gitlab.com/danbarry16/pandoc-highlight-filter/-/blob...
I have been adding some JavaScript through the years. Some for generating content, some for graphics and animations. I also have written a C program for checking the HTML and all the internal links and the use of tags. The program places all updated files into a folder ready for upload with FTP.
To edit the HTML, I use an editor (based on Crystal Edit) that also can navigate HTML files: when pressing F5 on a link, it opens the file in the editor (or in the default browser when it is an external link), and if there a tag in the link, positions the cursor at that line.
See for more details: https://www.iwriteiam.nl/SiteMain.html
My question is how do you update your feed, sitemap and other stuff?
I've been doing it by shell scripts, I'm not 100% satisfied, I also create gemini pages from HTML, which changes content a lot.
Another question: how do you handle comments to your posts?
Because my blog is a static site, so there is no processing on the server end, and I don't want third parties to handle this. What I've done is adding a handler to my mail server, so it writes the mail sent to articles to the right place. And the HTML uses an <object> to load them. I don't like it either, but works. Any suggestions for this things?
Thanks!
haven't tried this but maybe you could do that all in PHP and run `php feed.php > feed.html` or something regularly . and now I just realized you said you've been doing it with shell scripts and that's pretty much the same thing, maybe you could use a cron job or something.
I know a lot of people don't like PHP but I believe it's still the best/simplest way to just "make my HTML run code please". and it's improved a lot in recent years as well. of course if you want to use another language you can.
>Another question: how do you handle comments to your posts?
you could use something like Disqus or one of the alternatives. there are self hosted ones if you really don't trust third parties but then you might as well run the web server on there (and run PHP normally).
also just wondering how are you using <object> for this?
<footer>
<hr>
<h3>Responses:</h3>
<object data=/mail/uptime.html type=text/html></object>
<a href="mailto:reply@blog.terminal.pink?subject=uptime">
reply
</a>
</footer>
so when I receive an email it is appended to this mail/uptime.html file.I don't like it because I wanted it to be just one p for each email, but the object has a whole page, like head, stylesheet, and it's separated from the outside context in some ways, not really sure.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/po...
https://en.wikipedia.org/wiki/Server_Side_Includes
Also, other than to satisfy a purist desire, why do you need this?
You can pre-render HTML quickly using a variety of template systems, and it would outperform what you are suggesting every time (from a client's perspective). I mean, think about the potential CSS resolution complexity, FOUC, etc.
https://caddyserver.com/docs/modules/http.handlers.templates
The "include" function should do the job:
{{include "path/to/file.html"}}
https://nginx.org/en/docs/http/ngx_http_ssi_module.html
Caddy chose not to, I guess?
https://caddy.community/t/caddy-update-on-ssi-server-side-in...
Or serializing `<template>`s without needing JS. Like in lists (`<ol>`, `<ul>`, `<dl>`...). All in all `<template>`s are a nice thing to have, and I do use them a lot (like in my own portfolio), but it feels really lacking without JS.
It has sadly been replaced by a website made in Framer due to time constraints, but the old version is on the Wayback Machine:
https://web.archive.org/web/20211008131609/https://tonari.no...
Unfortunately it kinda turned into a flickery mess, not sure if that's an old bug of ours or something failing to load properly from the archive. Oh well!
<!--# include file="/menu.html" -->
...
<!--# include file="/footer.html" -->
This type of ssi templating is extremely useful for static HTML sites using .html (and other) files on filesystems. I've been using it since hosting my website on my 56k modem in 1999 with Xitami server on Win98. Now I do it hosting from my cable modem in 2025 with nginx on linux.Amazing how such a simple mechanism can remain useful even decades later.
I already had a PHP website, and I wanted to add a simple blog system to it, but most suggestions were complex systems that required installation.
I created a .htaccess file and some PHP files to load and display markdown files from the /posts folder.
It doesn't require installation (just copy-paste the files and you have a blog), and no database (posts are simply the markdown files).
https://parkscomputing.com/page/conways-game-of-life
Is supported underneath by the raw HTML:
https://parkscomputing.com/content/conways-game-of-life.html
The menu and main page are controlled by a JSON configuration.
The site is slow right now because I'm being stingy on the Azure storage performance.
> Why? It took me hours of Googling
After
> How? I spent some time looking around for guides or a “canonical” way of doing this and found that there isn’t really one.
Sounds like no benefit in reducing the costs to achieve a less functional site (see next steps, which would require more googling)
While I am a programmer, I will continue to write code that injects html text with another... like a layout having a title and body html, etc.
I certianly limit my client-side codebase. Most of my javascript code is really focused on GUI/UI, even if I have to use a specific library. I dont bother with React or the like.
I will use htmx if I want to do partial updates. Other pages might be a tad more complicated if fetching data from SQL. However, I also have pages that are SIMPLY HTML+CSS!!
As I say - plain and simple.
Do I have Stockholm syndrome or is the code here completely fine?
Yes, it probably is a good idea to use technologies you understand. But you not understanding Svelte isn't a Svelte problem.
I use PHP+Twig on my simple websites just so I don't have to copy-paste the header/footer/nav. It's still incredibly simple, very close to HTML+CSS and no build times. You can FTP upload your files if you want it works.
https://github.com/tests-always-included/mo.
Took just a few minutes to setup. E.g. https://afarah.info/public/blog/awsv3/index.html.
Writing in Markdown with {{mustache}} templates for DRY is very satisfying, a simple bash script renders it. Looks good on my phone even.
I'm no front-end developer by any means, but arent native web components a thing now ?
https://developer.mozilla.org/en-US/docs/Web/API/Web_compone...
[1]: https://developer.mozilla.org/en-US/docs/Web/API/Web_compone...
The new paradigm of adding “use server”, “use cache”, and “use client” felt too magical by default.
Server actions are easy to forget adding validation and proper access control on. You need an external library to avoid the common pit falls.
I’ve been contemplating whether to move to something simple. The complexity creep is real.
I looked at your site, and if that's anything more than a single static HTML file with some resources, served by a web server, something strange is going on. There is nothing complex on your site that requires more than a handful of lines of inline JS (to shuffle the letters).
The site also scrolls slowly, especially noticeable on phones. If this was just plain HTML it wouldn't.
It feels like the baseline for web developers has become that you MUST first add a ton of extremely complex dynamic stuff, and only then can you even think about putting a single line of text on the page. There's 200kB of code being loaded for this website, what is it doing?
I had this exact same surprise last year! For whatever reason, there really isn't any sort of standard way of creating a vanilla site in 2025!
The only thing I have is a blog post navigator, that shows you all blog posts besides the current one.
Something I built to have my own site in static HTML and CSS.
as always: imho.
ad "duplicated (html) code" in static webpages:
back in the 1990ties when a lot of people wrote html by hand, there was a thing called "server side includes" ...
* https://en.wikipedia.org/wiki/Server_Side_Includes
or just use some "ubiquitous" script-language like php for this simple task of orchestrating/including snippets/components of code etc. :)
just my 0.02€
Couldn't the code highlighting be also handled statically during the build process?
it’s simple and maintainable.
Node calls pandoc, which converts my markdown into HTML, ESBuild to convert the few JS snippets I run on my site (which I write in TS), and SASS to convert my scss stylesheet into a bundled CSS sheet.
It's super lightweight and I like that I can bend it to do whatever weird shit I want my site to have without relying on a 3rd party static site generator.
[^1]: https://pfy.ch
- consider using an HTML boilerplate template like this one if you don't know where to start: https://www.matuzo.at/blog/html-boilerplate/
- consider using a CSS template, or a CSS reset, if you don't know where to start with styling. Pico CSS is a good drop-in: https://picocss.com/. Frontend devs always blog about their CSS resets, like this one: https://piccalil.li/blog/a-more-modern-css-reset/. But if you're someone inclined to write their own HTML, then you'll probably also want to write your own CSS. This takes time to learn. Especially learning how to design the page without looking crappy
- I copy my last page as a template whenever writing a new page
- I don't worry about code duplication. If I need to refactor duplicated content, I use search and replace across files in vim (like https://nithinbekal.com/posts/vim-search-replace/). Hopefully your editor/IDE has something similar, and hopefully you're comfortable with regexes
- markdown + pandoc + scripting is a common solution. Technically it's not handwriting HTML at this point -- it's hacking together your own static site generator instead of using an existing framework -- but no biggie
- frontend people have made a lot of live reload tools over time. Here's a couple: https://nitoyon.github.io/livereloadx/ and https://github.com/tapio/live-server. Personally, I've cobbled together something with entr/caddy/websockets/userscripts. I've had problems with `python -m http.server` freezing up occasionally, but YMMV
- About RSS: you can generate your own feed if you already started your own generator script. Personally, I let this tool generate a feed for me in a GitHub Action: https://feed-me-up-scotty.vincenttunru.com/, but the feed quality is meh
- Expect to do a lot of fiddling. You'll reinvent things. You'll lack common features for a while. Embrace this as minimalism. You'll begin to appreciate the tasks that frameworks automate (image optimization, compression, meta tags, validation, etc)
- You'll face growing pains after you cross certain thresholds of page counts. Personally, I'd rather be grug-brained and edit more HTML than figure out some new framework. This is fine for a personal website with a straightforward structure