<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Louis Austke</title>
    <description>The latest articles on DEV Community by Louis Austke (@laustke).</description>
    <link>https://dev.to/laustke</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1208898%2F8874dc2c-a679-4704-baa9-526f33a77b5a.jpg</url>
      <title>DEV Community: Louis Austke</title>
      <link>https://dev.to/laustke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/laustke"/>
    <language>en</language>
    <item>
      <title>Local Text-to-Speech is finally practical on CPU-only machines</title>
      <dc:creator>Louis Austke</dc:creator>
      <pubDate>Fri, 23 Jan 2026 04:15:57 +0000</pubDate>
      <link>https://dev.to/laustke/local-text-to-speech-is-finally-practical-on-cpu-only-machines-gal</link>
      <guid>https://dev.to/laustke/local-text-to-speech-is-finally-practical-on-cpu-only-machines-gal</guid>
      <description>&lt;p&gt;Until recently, getting natural-sounding text-to-speech usually meant using a hosted service. If you wanted good quality, you ended up calling an API from Amazon, Microsoft, or Google. That works, but it means relying on a remote service and paying per use for a task that doesn't inherently need to be remote.&lt;/p&gt;

&lt;p&gt;There are now models that run fast enough on a regular CPU to be useful in practice. They don't need a GPU, and the audio quality is comparable to what you get from common cloud TTS services. Everything runs locally, without relying on third-party APIs.This aligns well with the expectations of privacy-oriented users.&lt;/p&gt;

&lt;p&gt;I wanted to make local, CPU-only text-to-speech conversion usable without requiring people to understand or assemble the underlying tooling, so I built a simple GUI converter that can convert long texts to speech in a matter of minutes.&lt;/p&gt;

&lt;p&gt;It supports basic desktop workflows like drag and drop, which makes it more convenient than uploading text to a service and downloading the generated audio files. You can drop in text files, run batch conversions, and get audio files out, all locally.&lt;/p&gt;

&lt;p&gt;This is what the main conversion tab looks like while a conversion is running. The focus is on keeping the workflow simple and local: drop text files, process them in batches, and get audio files out without external services.&lt;/p&gt;

&lt;p&gt;Here's what the main conversion tab looks like while a conversion is running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk88qtb0l3div99w9bs3i.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk88qtb0l3div99w9bs3i.webp" alt=" " width="800" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application is free and runs entirely offline. Project details and downloads are available at &lt;a href="https://jimlet.com" rel="noopener noreferrer"&gt;https://jimlet.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This project exists because CPU-only text-to-speech is finally fast enough to be useful. That makes it practical to build local tools that don't rely on cloud APIs or specialized hardware, and to keep them simple and self-contained.&lt;/p&gt;

</description>
      <category>tts</category>
      <category>ai</category>
      <category>python</category>
      <category>software</category>
    </item>
    <item>
      <title>I created a video tutorial on how to make a responsive sidebar using CSS and vanilla Javascript</title>
      <dc:creator>Louis Austke</dc:creator>
      <pubDate>Thu, 24 Oct 2024 22:58:55 +0000</pubDate>
      <link>https://dev.to/laustke/i-created-a-video-tutorial-on-how-to-make-a-responsive-sidebar-using-css-and-vanilla-javascript-3ofi</link>
      <guid>https://dev.to/laustke/i-created-a-video-tutorial-on-how-to-make-a-responsive-sidebar-using-css-and-vanilla-javascript-3ofi</guid>
      <description>&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=qfnnAIUf_yw" rel="noopener noreferrer"&gt;Part One: Building a Responsive Drawer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=yLHGqF6gAK0" rel="noopener noreferrer"&gt;Part Two: Building a Vertical Navigation Menu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I coded a vertical, two-level, responsive navigation sidebar from scratch using vanilla JavaScript and CSS, without frameworks, preprocessors, or any build/compilation process, and described the process in detail in two YouTube tutorials.&lt;/p&gt;

&lt;p&gt;This sidebar can be used as the foundation for a simple website or web application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filkx5qfpks6aq4z3yukt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filkx5qfpks6aq4z3yukt.gif" alt="Image description" width="730" height="830"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nav</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A one-stop comparison of several synthetic and human voices</title>
      <dc:creator>Louis Austke</dc:creator>
      <pubDate>Sun, 11 Feb 2024 21:36:08 +0000</pubDate>
      <link>https://dev.to/laustke/a-one-stop-comparison-of-several-synthetic-and-human-voices-579d</link>
      <guid>https://dev.to/laustke/a-one-stop-comparison-of-several-synthetic-and-human-voices-579d</guid>
      <description>&lt;p&gt;For the impatient: Go to the &lt;a href="https://cloudtts.com/compare-voices/"&gt;Voice Comparison Page&lt;/a&gt; to test the voices right away.&lt;/p&gt;

&lt;p&gt;It's no secret that &lt;strong&gt;text-to-speech&lt;/strong&gt; technology has made significant advancements recently, with voices now sounding almost as natural as human voices. Major giants in the field include Google, Amazon, and Microsoft, alongside smaller companies like &lt;a href="https://elevenlabs.io/?from=partnerwalton3090"&gt;ElevenLabs&lt;/a&gt;, which boasts of providing the most hyper-realistic &lt;strong&gt;voice generator&lt;/strong&gt; on the market. Actually, the spectrum of these smaller companies is so diverse that making a direct comparison and deciding for yourself which voice is better becomes difficult.&lt;/p&gt;

&lt;p&gt;Usually, the voice example page is deeply embedded within the documentation of a text-to-speech API, requiring you to navigate between several sites and generate speech for various text snippets to form your judgment. So, to simplify the comparison process, I collected all of them on one page. I compiled a set of text snippets that imitate commonly used topics for voiceovers and created audio files where these texts are read by all the voices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlighting words
&lt;/h3&gt;

&lt;p&gt;I wanted the words to be karaoke-style highlighted while the text is spoken. First of all, this is visually pleasing, and it makes the text much easier to follow. So, for every audio file, I created a speech mark file that contains a list of pairs, each consisting of a word and the time when its pronunciation starts.&lt;/p&gt;

&lt;p&gt;Microsoft, Amazon Polly, and Google provide this functionality. It is referred to differently - marks, speech marks, or subtitles. Essentially, alongside the events when audio is generated, there are other events like 'WordBoundary' that include supplementary information, such as the starting time.&lt;/p&gt;

&lt;p&gt;I have a 'highlightWord' function that highlights the word in the textbox. When the audio player starts playing the speech file, this function is scheduled to run multiple times, each at the starting time when a specific word is pronounced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;audioPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onplay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="nx"&gt;scheduledHighlightWordIDs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;speechMarks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeoutId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;highlightWord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;scheduledHighlightWordIDs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I keep the timeout IDs so that I can unschedule the function, for example, when playing is interrupted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-fetching audio
&lt;/h3&gt;

&lt;p&gt;Another problem I faced was the desynchronization of speech and highlighting when I provided a URL for the MP3 file to the Audio Player. Apparently, depending on the user's connection speed, it takes a while to download and start playing the file, but the highlighting functions are scheduled immediately. The Audio Player has an option to notify the user when it has downloaded a sufficient portion of the audio content to start playing, but this was not good enough for me. I wanted to make sure that the entire file was downloaded before getting started. So, I pre-fetched the audio content into a blob, created a URL that represents the blob object in memory, and passed it to the Audio Player.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Cannot fetch url: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;audioUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;audioObjectUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;audioPlayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Audio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioObjectUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding real human voices
&lt;/h3&gt;

&lt;p&gt;Eventually, I thought, why stop here? So, I added recordings from actual voiceover artists to the comparison. Now, you can compare synthesized voices with real human voices to get a firsthand feel for the current state of text-to-speech technology.&lt;/p&gt;

&lt;p&gt;This is the link to the page: &lt;a href="https://cloudtts.com/compare-voices/"&gt;Compare Voices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, it's your turn to weigh in. Which synthetic voice do you find the most realistic? In a blind test, would you be able to tell AI-generated voices apart from those of actual voiceover artists?&lt;/p&gt;

</description>
      <category>tts</category>
      <category>speechsynthesis</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Ramblings on HTML Page Structure and Bootstrap</title>
      <dc:creator>Louis Austke</dc:creator>
      <pubDate>Sat, 06 Jan 2024 15:32:06 +0000</pubDate>
      <link>https://dev.to/laustke/ramblings-on-html-page-structure-and-bootstrap-2h2a</link>
      <guid>https://dev.to/laustke/ramblings-on-html-page-structure-and-bootstrap-2h2a</guid>
      <description>&lt;p&gt;When people talk about the &lt;a href="https://getbootstrap.com/"&gt;Bootstrap CSS framework&lt;/a&gt;, the conversation usually revolves around CSS classes: there is this class and that class, and this is how to display a primary button on a webpage.&lt;/p&gt;

&lt;p&gt;However, Bootstrap is, essentially, a declarative language. It describes how a web page is supposed to look like.&lt;/p&gt;

&lt;p&gt;In a sense, regular HTML/CSS describe the same thing, but on a lower level: they define block elements, inline elements, and how you can position them on a page. Bootstrap is a higher-level language typically used to describe webpages in more generic terms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure of a webpage
&lt;/h2&gt;

&lt;p&gt;If you take a look at the typical homepage of almost any website, you'll see they all have a similar structure. First comes the menu, followed by several sections containing the main content, and then the footer.&lt;/p&gt;

&lt;p&gt;How is it expressed by the bootstrap? &lt;/p&gt;

&lt;p&gt;In Bootstrap, the menu is a special and probably the most complex component. Bootstrap features a horizontal dropdown menu that, on smaller screens, is replaced by a vertical menu with a hamburger button. The Bootstrap menu deserves its own separate discussion, which I won't go into right now.&lt;/p&gt;

&lt;p&gt;Following the menu are several page sections. A section is essentially a horizontal band containing various elements. Usually, you need to define the distance between this section and the previous one.&lt;/p&gt;

&lt;p&gt;How can we describe this, loosely drawing on an analogy of objects with properties and values?&lt;/p&gt;

&lt;h2&gt;
  
  
  Section
&lt;/h2&gt;

&lt;p&gt;If we were to define 'Section' as an object with properties, it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Section&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Product Features&lt;/span&gt;
    &lt;span class="na"&gt;margin-top&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;margin-right&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="na"&gt;margin-bottom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;margin-left&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is how it is done in bootstrap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"product-features my-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "my-3" class specifies vertical margins (along the 'Y' axis) - both top and bottom margins - with a value of '3' on Bootstrap's spacing utility scale. This scale ranges from 0 to 5, where '0' implies no space between sections and '5' indicates maximum spacing, creating a significant gap. Thus, '3' provides a moderate amount of vertical space, ensuring the sections are neither too close nor too far apart. &lt;/p&gt;

&lt;p&gt;If your perception of 'very far apart' differs from that of the Bootstrap creators, or if you need more steps to define your own distance scale, you have the option to customize it yourself. &lt;/p&gt;

&lt;p&gt;Continuing with the 'Section' object from our earlier analogy, you set the values for its 'margin-top' and 'margin-bottom' properties in this way.&lt;/p&gt;

&lt;p&gt;Now that we have placed a section on the page, we can concentrate on what's inside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Container
&lt;/h2&gt;

&lt;p&gt;Normally, we don't want our text to stick to the left border of the page; instead, we prefer to give it a bit of a margin. To ensure aesthetic appeal, the size of this margin should vary for different screen sizes. This important consideration is expressed in Bootstrap as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Naturally, I am oversimplifying things, and there is more to the 'container' than this, but for now on, here is the rule: Inside every section, there should be a container.&lt;/p&gt;

&lt;h2&gt;
  
  
  12 column grid
&lt;/h2&gt;

&lt;p&gt;Often, the content we want to place inside the container doesn't span the full width. For example, we might have an image on the left side and some text on the right side. This is where the grid system comes into play.&lt;/p&gt;

&lt;p&gt;It consists of 12 columns because this allows for easy division of the full width into halves, thirds, quarters, and combinations like 3/4 and 1/4 without referring to ratios.&lt;/p&gt;

&lt;p&gt;In any case, simple two column grid looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Left
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Right
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bootstrap is designed to accommodate different screen sizes, and for many classes, there is a way to specify the screen size to which the feature applies. If you want your content to be placed in two columns on medium or larger screens, you can use 'col-md-6'. In this case, on devices with smaller screens, the columns will stack vertically, one below the other.&lt;/p&gt;

&lt;p&gt;The concept of columns in Bootstrap is so integral that even when defining full-width content, it is often described as a single-column cell spanning the full width.&lt;/p&gt;

&lt;h2&gt;
  
  
  Centered content and offsets
&lt;/h2&gt;

&lt;p&gt;When you want centered content that occupies a certain percentage of the full width, it's achieved using a column with an offset. Imagine you have 12 vertical bands, and you want to place something in the middle of your section that is approximately half wide.&lt;/p&gt;

&lt;p&gt;You say&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-6 offset-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         Centered content
     &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essentially, 3 left vertical bands are left empty, then comes your column, which is 6/12 or 1/2 of the width. Then, two more bands are left empty, although this is not described explicitly.&lt;/p&gt;

&lt;p&gt;Again, you can decide that on smaller screens the offset should be smaller or even disappear completely. This is achieved using appropriate size modifiers, such as 'offset-md-2' and similar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Footer
&lt;/h2&gt;

&lt;p&gt;The footer is a special kind of section that is placed at the very bottom of your page. There is a special HTML tag for it, , similar to the  tag used for headers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final page structure
&lt;/h2&gt;

&lt;p&gt;So, this is what the outline of a &lt;/p&gt; element on a typical Bootstrap HTML page looks like:&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Navigation bar --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Header --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Multiple sections --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"product-features my-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    Left
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-6"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    Right
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    ... repeat

    &lt;span class="c"&gt;&amp;lt;!-- Footer --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;footer&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;There are libraries that describe GUI interfaces declaratively, for example, through XML. You have two options: either build your interface by directly creating GUI objects like Frames, Textboxes, etc., or create them from an XML description. In the latter case, a Window (or Page) object with the appropriate widgets and GUI controls will be created.&lt;/p&gt;

&lt;p&gt;So, in this case, the Bootstrap framework is a tool used to declaratively describe a typical HTML page and its common elements. It is the browser that renders this description and creates the actual GUI objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the alternatives?
&lt;/h2&gt;

&lt;p&gt;Many people advocate for writing everything from scratch. While CSS has greatly improved since the time when tables were used for layout, and now we have CSS Flexbox and CSS Grid layouts, there is still much more complexity than it appears.&lt;/p&gt;

&lt;p&gt;For example, Bootstrap uses different fonts for headers on devices with various screen sizes. Building a responsive dropdown menu would be an especially daunting task on its own. Yes, it is possible, but would it be better than the regular Bootstrap menu?&lt;/p&gt;

&lt;p&gt;When I looked into the code of Bootstrap pages, I always thought they were too verbose with all these lengthy "mt-3 mb-2 py-md-1 offset-lg-4" class names. Not to the extent of Tailwind CSS's verbosity, but still, from my perfectionist perspective, HTML sections should only contain the class name, with the rest of the styling defined via CSS.&lt;/p&gt;

&lt;p&gt;Now, I'm not so sure. I am ready for compromises. I am even okay with creating columns with single full-width cells, as long as it provides consistency and helps me understand the myriad examples of Bootstrap template code out there.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>design</category>
      <category>html</category>
    </item>
  </channel>
</rss>
