|
1 | | -<script> |
| 1 | +<script lang="ts"> |
2 | 2 | import ConnectedButtons from "$lib/buttons/ConnectedButtons.svelte"; |
3 | 3 | import Button from "$lib/buttons/Button.svelte"; |
4 | 4 | import Snippet from "../Snippet.svelte"; |
5 | 5 | import { appType } from "../../state"; |
| 6 | + import Switch from "$lib/forms/Switch.svelte"; |
| 7 | +
|
| 8 | + let useCompression = $state(true); |
| 9 | + const uc = (uncompressed: number, compressed: number) => |
| 10 | + useCompression ? compressed : uncompressed; |
6 | 11 | </script> |
7 | 12 |
|
8 | 13 | <svelte:head><title>Walkthrough</title></svelte:head> |
|
134 | 139 | <code class="styles-defined">@apply --m3-focus-none</code>). |
135 | 140 | </p> |
136 | 141 |
|
| 142 | +{#snippet color(c: string, label: string)} |
| 143 | + <span class="color" style:color="color-mix(in oklab, currentColor, {c} 30%)"> |
| 144 | + <span style:background-color={c}></span> |
| 145 | + {label} |
| 146 | + </span> |
| 147 | +{/snippet} |
| 148 | +{#snippet stackedBars(title: string, nums: number[])} |
| 149 | + <div class="stacked-bars-container"> |
| 150 | + <h4>{title}</h4> |
| 151 | + <div class="stacked-bars"> |
| 152 | + {#each nums as n} |
| 153 | + <div style:width="{(n / 100) * 100}%" title="{n.toFixed(2)}kB"></div> |
| 154 | + {/each} |
| 155 | + </div> |
| 156 | + </div> |
| 157 | +{/snippet} |
| 158 | + |
| 159 | +<h2>Versus other libraries</h2> |
| 160 | +<p> |
| 161 | + We tested the sizes of the {@render color( |
| 162 | + "var(--m3c-primary-container-subtle)", |
| 163 | + "framework baseline", |
| 164 | + )}, {@render color("var(--m3c-primary-container)", "library baseline")}, and {@render color( |
| 165 | + "var(--m3c-primary)", |
| 166 | + "full size to render a Button", |
| 167 | + )}. |
| 168 | +</p> |
| 169 | +<label> |
| 170 | + <Switch bind:checked={useCompression} /> |
| 171 | + Use compression |
| 172 | +</label> |
| 173 | + |
| 174 | +<h3>M3 Svelte (SvelteKit)</h3> |
| 175 | +<p>Built using token-shaker.</p> |
| 176 | +<p>Takes {uc(1.148 + 1.22 + 5.87, 0.609 + 0.62 + 1.33).toFixed(1)}kB to render a Button.</p> |
| 177 | +{@render stackedBars("HTML", [uc(1.148, 0.609), uc(0.985, 0.535), uc(0.842, 0.483)])} |
| 178 | +{@render stackedBars("CSS", [uc(1.22 + 5.87, 0.62 + 1.33), uc(0.63 + 0.85, 0.31 + 0.46), 0])} |
| 179 | +{@render stackedBars("JS (optional)", [uc(78.03, 37.75), uc(67.45, 33.04), uc(63.74, 30.74)])} |
| 180 | + |
| 181 | +<h3>M3 Svelte (Vite)</h3> |
| 182 | +<p>Built using token-shaker.</p> |
| 183 | +<p>Takes {uc(0.38 + 7.08 + 37.43, 0.26 + 1.78 + 14.41).toFixed(1)}kB to render a Button.</p> |
| 184 | +{@render stackedBars("HTML", [uc(0.38, 0.26), uc(0.38, 0.26), uc(0.3, 0.22)])} |
| 185 | +{@render stackedBars("CSS", [uc(7.08, 1.78), uc(1.48, 0.67), 0])} |
| 186 | +{@render stackedBars("JS", [uc(37.43, 14.41), uc(23.5, 9.22), uc(19.82, 7.95)])} |
| 187 | + |
| 188 | +<h3><a href="https://material-web.dev/">Material Web</a> (Vite)</h3> |
| 189 | +<p>Material Web uses web components, but isn't maintained.</p> |
| 190 | +<p>Takes {uc(0.35 + 45.5, 0.24 + 13.53).toFixed(1)}kB to render a Button.</p> |
| 191 | +{@render stackedBars("HTML", [uc(0.35, 0.24), uc(0.3, 0.22), uc(0.3, 0.22)])} |
| 192 | +{@render stackedBars("JS", [uc(45.5, 13.53), uc(25.42, 9.23), uc(15.39, 5.91)])} |
| 193 | + |
| 194 | +<h3><a href="https://matraic.github.io/m3e/">M3E</a> (Vite)</h3> |
| 195 | +<p> |
| 196 | + M3E uses web components, but is vibe coded, so some of the components look weird. It also has |
| 197 | + numerous extraneous components. |
| 198 | +</p> |
| 199 | +<p>Takes {uc(0.34 + 155.25, 0.24 + 32.31).toFixed(1)}kB to render a Button.</p> |
| 200 | +{@render stackedBars("HTML", [uc(0.34, 0.24), uc(0.3, 0.22), uc(0.3, 0.22)])} |
| 201 | +{@render stackedBars("JS", [uc(155.25, 32.31), uc(87.28, 21.33), uc(15.39, 5.91)])} |
| 202 | + |
| 203 | +<h3><a href="https://m3dl.r58playz.dev/">M3 Dreamland</a> (Vite)</h3> |
| 204 | +<p> |
| 205 | + M3 Dreamland uses Dreamland, a minimal, experimental web framework. Dreamland is built for |
| 206 | + client-side apps; it can do SSR, but you have to configure prerendering and such manually. |
| 207 | +</p> |
| 208 | +<p>Takes {uc(0.3 + 131.12, 0.22 + 29.04).toFixed(1)}kB to render a Button.</p> |
| 209 | +{@render stackedBars("HTML", [uc(0.3, 0.22), uc(0.3, 0.22), uc(0.3, 0.22)])} |
| 210 | +{@render stackedBars("JS", [uc(131.12, 29.04), uc(91.32, 23.29), uc(7.77, 3.83)])} |
| 211 | + |
| 212 | +<h3><a href="https://m3dl.r58playz.dev/">M3 Solid</a> (Vite)</h3> |
| 213 | +<p>Coming soon. Would show up <a href="https://github.com/PalmDevs">here</a>.</p> |
| 214 | + |
| 215 | +<h3><a href="https://www.beercss.com/">Beer CSS</a> (Vite)</h3> |
| 216 | +<p> |
| 217 | + Beer CSS is like a German startup - manually crafted, drinks lots of beer, no support for tree |
| 218 | + shaking, numerous extraneous styles, dark mode requires JS, doesn't really match M3, copies US |
| 219 | + code without credit... if you can't tell I have beef with their <em>un</em>seriousness. |
| 220 | +</p> |
| 221 | +<p>Takes {uc(0.4 + 192.49, 0.27 + 36.75).toFixed(1)}kB to render a Button.</p> |
| 222 | +{@render stackedBars("HTML", [uc(0.4, 0.27), uc(0.37, 0.25), uc(0.3, 0.22)])} |
| 223 | +{@render stackedBars("CSS", [uc(192.49, 36.75), uc(192.49, 36.75), 0])} |
| 224 | +{@render stackedBars("JS (optional)", [uc(12.03, 4.24), uc(12.03, 4.24), 0])} |
| 225 | + |
| 226 | +<h3>Fun fact</h3> |
| 227 | +<p> |
| 228 | + Most of Svelte and M3 Svelte's optimizations show up in this simple demo. For example, you can see |
| 229 | + how Svelte let the button be rendered with just HTML and CSS, and how the CSS that was shipped was |
| 230 | + optimized to the specific component. But you could tip the scale even further by adding an icon. |
| 231 | + Material Web, M3E, and Beer CSS pull in <em>all icons</em> (by default) through an icon font, which |
| 232 | + can weigh nearly 300kB. |
| 233 | +</p> |
| 234 | + |
137 | 235 | <style> |
138 | 236 | p { |
139 | 237 | margin: 0; |
|
177 | 275 | border-radius: var(--m3-shape-small); |
178 | 276 | align-self: start; |
179 | 277 | } |
| 278 | +
|
| 279 | + .color { |
| 280 | + display: inline-flex; |
| 281 | + align-items: center; |
| 282 | + gap: 4px; |
| 283 | + > span { |
| 284 | + width: 12px; |
| 285 | + height: 12px; |
| 286 | + border-radius: var(--m3-shape-full); |
| 287 | + } |
| 288 | + } |
| 289 | + label { |
| 290 | + display: flex; |
| 291 | + align-items: center; |
| 292 | + gap: 0.5rem; |
| 293 | + } |
| 294 | + .stacked-bars-container { |
| 295 | + display: flex; |
| 296 | + @media (width < 37.5rem) { |
| 297 | + flex-direction: column; |
| 298 | + } |
| 299 | + gap: 0.5rem; |
| 300 | + max-width: 100ch; |
| 301 | + } |
| 302 | + .stacked-bars-container > h4 { |
| 303 | + @apply --m3-title-small; |
| 304 | + width: 5rem; |
| 305 | + margin: 0; |
| 306 | + align-self: center; |
| 307 | + } |
| 308 | + .stacked-bars { |
| 309 | + display: flex; |
| 310 | + height: 64px; |
| 311 | + flex-grow: 1; |
| 312 | + position: relative; |
| 313 | + > * { |
| 314 | + position: absolute; |
| 315 | + inset: 0 auto 0 0; |
| 316 | + border-radius: var(--m3-shape-small); |
| 317 | + } |
| 318 | + > :nth-child(1) { |
| 319 | + background-color: var(--m3c-primary); |
| 320 | + } |
| 321 | + > :nth-child(2) { |
| 322 | + background-color: var(--m3c-primary-container); |
| 323 | + } |
| 324 | + > :nth-child(3) { |
| 325 | + background-color: var(--m3c-primary-container-subtle); |
| 326 | + } |
| 327 | + } |
180 | 328 | </style> |
0 commit comments