It allows interested parties to get a filterable list of all the apps, big and small, that use a given API.
Need to prove that we're building obscure-sounding APIs like the Web Serial API for a reason? Select the API's chip and there goes a list of all the apps that use it:
Of course the Project Fugu API Showcase is contained in itself (yay, recursion 🎉), which means on supporting browsers you can use it to share it (or any other of the contained apps) with your followers:
Please help spread the word and use this in discussions with the people you work with (whose apps you—or they—are obviously most welcome to add to the showcase):
I'm following the
(Twitter) conversation
on browser engines other than WebKit to be allowed on iOS very closely. When the
United Kingdom's Competition and Markets Authority (CMA)
solicited responses
from Web developers to their
mobile ecosystems market study interim report,
I
sent one
where I spoke as the developer of SVGcode and told the CMA
about my experience with making the app performantly available on iOS Safari:
To whom it may concern,
I'm an employee of Google Germany, but also a hobbyist Web developer.
Recently, I have built an application, SVGcode (https://svgco.de/), which I
wanted to be performing well on all browsers, so I have put a lot of time and
effort into making it as compatible and progressively enhanced as I could.
Unfortunately, Safari is the one browser that constantly requires the most
hoops to get to the same baseline experience as on other browsers like
Firefox, Edge, or Chrome.
For example, it does not offer proper installation support, so rather than use
my built-in Install button, I need to hope my users are aware of the hidden
away "Add to Home Screen" feature in Safari.
Another missing feature is OffscreenCanvas, which would greatly improve the
app's performance, but as is, the performance on Safari leaves to be desired.
On macOS, I can just tell users that I have made the maximum effort to be
compatible with all browsers, but if people wish to get the maximum
performance, they are free to switch their browser to a one with the maximum
amount of features supported.
On iOS and iPadOS, however, there is nothing I could tell my users, since even
alternative browsers have to use WebKit's rendering engine under the hood. I
do hope your legislation can help improve upon the situation and lift Apple's
browser ban.
Respectfully yours,
Thomas Steiner
——
P.S. While I am employed by Google, I am speaking in a personal capacity for my
work as a hobbyist developer outside of Google.
More impactful and lawyer-approved than mine are the responses from Mozilla
and Google, though, which I invite you to read in their entirety. Below just
two significant quotes:
Without regulatory intervention we believe there will be no change to the
status quo, harming competition in browser engines and browsers, and harming
innovation
online.—Mozilla
Competition between browser engines—and freedom of choice for developers—means
browser apps on Android can differentiate themselves by incorporating a range
of features and functionalities that are not available on iOS, where all
browsers are required to use Apple's WebKit browser
engine.—Google
(It goes without saying but restating again: While I am employed by Google, I am
speaking in a personal capacity for my work as a hobbyist developer outside of
Google.)
Just a quick note to say that I have released SVGcode, a
Progressive Web App that lets you convert raster images like JPG, PNG, GIF,
WebP, AVIF, etc. to vector graphics in SVG format. You can find the
source code on GitHub.
SVGcode is starting to get some coverage, for example, from
XDA Developers and even a
Chinese website called
软餐.
To help discoverability, I have also listed it on
Stefan Judis' collection of
Tiny Helpers. With the orange
site it is always give and take, but for now (🤞),
Hacker News treats the app
quite well. Looking forward to seeing where the app goes.
You can recognize things mode by looking at the q query parameter in the
URL. If it starts with %2Fg%2F (URL-decoded: /g/), you are in things mode.
The funny code 11bzxympx6 after that is the
Knowledge Graph identifier. When
you
search for "11bzxympx6" on Google,
you end up with exactly one search result that points to the
Wikidata page for Progressive Web Apps.
If you know the Knowledge Graph ID of something, you can hand-craft a URL that
points people at exactly the right semantic search result on Google:
https://www.google.com/search?kgmid=/g/11bzxympx6.
See the bold Knowledge Graph ID at the end of the URL.
Note how Google Trends in the screenshot above even helpfully points out that…
[t]his comparison contains both Search terms and Topics, which are measured
differently.
…and directs the reader to a
help resource
to learn more about the difference.
I happen to know all this because this is what I did my PhD in, and I have
a paper at the ACM that
describes the process we used for migrating our proprietary Knowledge Graph
predecessor Freebase to the community-maintained Wikidata.
It's rare that I get to tell anyone about this stuff, so now you know more than
you probably wanted to ever hear about this… You can learn more about this time
of my Google life in my previous
blog post.
My manager back in the days didn't care about any of this, but maybe it's at
least interesting to you… :-)
Yesterday marked my 14 year Googleversary. I joined Google full time on
October 1, 2007 as a new-grad straight from university. While for the
Googleversary stats all that counts is full time employment, I was with Google
way earlier. First as an intern between my second and third year at university
starting on February 1, 2005, and then continuously throughout the rest of
my studies as a temporary worker and via other internship contracts. The way
this actual employment age shows is through the employee ID. Mine is in the
9,000 range, but people who joined about the time when I joined full-time have a
50,000 range ID. At the time of writing, 98.08871% of full time employees and
extended workers have been at Alphabet for less time than me. During these
14 years, I've had 15 managers, some of them multiple times. I have
2.85-ified my salary (sounds impressive maybe, but I simply started very low),
and have gone through three promotions. That's one promotion less than I think I
could have had, but instead I enjoyed a different perk: I did my PhD on company
time.
While I wanted to do a PhD after three years on the job, I wasn't initially
planning on doing it on company time. Quite the opposite. From February 1, 2010,
I had reduced my work load to 60% to work on my PhD in the remaining 40%. After
having this arrangement for two or three months, one evening my at the time
manager's manager called to make me an offer I couldn't resist: to come back
full time and work on I-SEARCH (A
unIfied framework for multimodal content SEARCH), a three-year European project
funded under FP7-ICT. This very
manager left the company a couple of months later and his successor didn't see
the same value in EU projects than the manager who left, and while they let me
continue my (multi-year) work, my previous (Strongly) Exceeds ratings that I
received for several quarters went down to regular Meets Expectations. Lesson
learned in hindsight:
Never make your personal work arrangement depend on the goodwill of a sole
manager, as powerful as this manager may appear.
During this time, I cranked out a number of
publications
(some of them fine, some of them mediocre), but above all made great friends and
traveled the world. You can see me co-present the result of the project, a
multimodal search engine, and to my surprise the
user interface of I-SEARCH is
still up.
My internship project—that sort of just evolved—was the Google AdWords PHP
client library APIlity. At the time,
the AdWords API (a very enterprise SOAP API) was brand new, and I happened to be
the intern who was able to make it work. I had some experience with REST APIs
from my
Master's thesis,
you can enjoy my first ever tech talk on the topic below.
During my first few full time years, I continued my work on the AdWords API as a
Customer Solutions Engineer, but my heart always was with developer advocacy. I
took on any opportunity I could get to hack my job and work with developers. One
of my best memories is the 2008 series of Google Developer Days, where we toured
all of Europe. Embedded below a presentation of mine on the Google Web Toolkit.
An advantage of the early years was that Google was a lot smaller and job roles
that were distinct in the US were still not present in Europe, so others like me
who were just somewhat technical enough needed to jump in and represent locally.
After finishing my PhD, I was (very naively so) disappointed that no one at the
company cared. No pay raise. No job offer. I actually had to beg to go back to
my previous Customer Solutions Engineer job that was the reason why I had
started the PhD in the first place. While I tried for a while to get hired
elsewhere and also switch jobs internally, nothing really worked out for various
reasons (mostly location constraints and failed interviews). Another lesson
learned:
Don't assume anyone in the company will care for your self-arranged further
education. Having a PhD or not makes a difference as a new hire, but not
later.
Location always was a big factor in what roles you could get at Google. I made
no secret of my interest in developer advocacy, but not being in one of the hub
engineering offices meant this door was closed. I lobbied
Paul Kinlan long enough until he eventually let me
apply for a role on the Chrome Developer Relations team. The time between the
interviews and the (thankfully positive) decision of the hiring committee was
one of the most nerve-wrecking in my life. Long story short, it took me more
than ten years to get the job I actually wanted. Not a real lesson, but more a
reflection:
Taking an educated risk and doing what you really want while doing just
enough to not get fired for doing too little of the things you actually get
paid for is a strategy that sometimes works out. I wouldn't recommend it,
unless you really, really want something.
Now I'm in Chrome Developer Relations since May 28, 2018 and it's an
honestly great team to be on. My work is about evolving the Web and making
things possible on the platform that were unthinkable before. I
spoke twice at Google I/O,
was part of Chrome Dev Summits, and presented at more international conferences
than I can remember.
Ironically the corona crisis demonstrated that location didn't matter that much
after all, at least for a distributed team like Chrome Developer Relations. Had
corona come a couple of years ago, maybe they would have let me apply for the
Developer Relations team way earlier, who knows. Since I started working for
Google, I always lived a ten minute walk away from the office, but despite this
short distance and even if I enjoy working in an office, I've now successfully
applied for my position to be permanently remote. Mostly to secure the right.
Is it time for the next gig? Maybe. It's very unusual for people in IT to stay
on the same job for as long as I did. Will I see 15 years at Google? Who
knows. Very probably so. For now, I'm definitely still having
fun, at least most of the days. Have I become more cynical? Definitely. Do I
panic when yet another re-org is being announced? Nope. One thing is certain,
though: my heart still beats for the Web. Reach out if you have questions on
anything that I wrote or if you want to discuss ideas. My
DMs are open and my email is right on my
About page.
It's not often that I post something with the Political tag
on my blog. In the recent months and probably years, I've in the majority
sticked to Technical posts, but this one is different. For
folks like me in tech, it's way too easy to limit oneself to just the mostly
uncontroversial (as in: it truly matters) technical stuff and stay silent
about other aspects of life. Yesterday, I watched the
Triell
(the TV debate between the three candidates for the German chancellor, Armin
Laschet, Olaf Scholz, and Annalena Baerbock) and I took this as an excuse to
make my political standpoint public. It's uncomfortable and I hesitated a lot,
but I think it's the right thing™ to do now.
As Annalena Baerbock from the
Grünen partysays: "The next
government is the last one that can still actively influence the climate
crisis." You may have heard of the
2021 floodings in Germany.
Our response can't be to rebuild and move on. If we continue the
laissez faire
of the German car industry that Mr. Laschet, the candidate of the Christian
Democratic Party CDU, demands, we mainly get electric (or worse, hybrid) SUVs
for 50K€+, but not affordable small cars for regular incomes. We don't need a
Merkel 2.0
that Mr. Scholz risks to become with a little bit of CO₂ pricing here and a
little bit of exit from coal energy there.
We need a politics where "[o]ur children, our grandchildren shouldn't have to
ask us: Why didn't you do anything? But: How did you do
it?"—Annalena Baerbock.
If you're not super familiar with the current German political pre-election
situation, here's some recommended background reading:
If you want to join me in going public with your political views, here's how I
did it. It may feel uncomfortable, "cost" you followers or subscribers to your
blog, or maybe even stop people from talking to you (I hope we keep talking,
even if we don't agree with each other), but I think it's worth it.
I tend to stick to tech content on Twitter, but the upcoming elections for the German @Bundestag 🇩🇪 are too decisive for this country’s future to remain silent about, so here’s my public statement of support for @ABaerbock and 🌻 @Die_Gruenen for #BTW21! Vote for the #climate! https://t.co/X0umn3EhsY
I was asked if one could use SVG web app manifest app icons that are reactive to prefers-color-scheme. To illustrate what this means, here is an excerpt of a manifest where I set the icon to an SVG that is reactive to the color scheme.
You can play with it by navigating directly to icon.svg and toggling your operating system's color scheme setting.
(Side remark about a little gotcha: Note how I need to "lie" about the icon's dimensions in the web app manifest, where I say it's 144x144 pixels compared to the width and height in the source code.)
So, to close this, the answer to the above question is yes, app icons will respect your preferred color scheme, but no, app icons won't update dynamically when you change your color scheme. Instead, they will keep their initial dark or light mode look from whatever you had your system set to at install time.
Google I/O 2020, like all the I/O conferences before, was planned as a physical event. But then the
coronavirus struck, and I/O 2020 was the I/O that never was. In 2021, we had enough time to plan, so
I/O 2021 was the first virtual event in the series.
The team outdid themselves and recreated the entire experience as a virtual game. As
Ars Technica wrote,
Google's I/O Adventure was almost as good as being there. To get a feel for it, here's
the official teaser video. During the event, you could bump into
Googlers and talk to them, almost like in the real world. Below, you can see a team photo we took at
the obligatory lighthouse. Can you spot me?
Together with @lipis, I had the pleasure of giving a talk titled
Excalidraw and Fugu: Improving Core User Journeys. You can watch the talk in the video embed
below, or read my video write-up over on web.dev.
I also created a codelab that covers a lot
of the Project Fugu 🐡 APIs. You can work your way through it at your own pace, or if you want,
re-join me in a virtual workshop session where you see me do it—and run into some minor service
worker caching issues… 😅
Google I/O 2021 was in my opinion a good event that worked OK enough under the circumstances and
with the constraints of the virtual format. With I/O in the books, we're looking what to do when it
comes to events in the future. Virtual, physical, or hybrid? The planning phase for Chrome Dev
Summit 2021 has already started… Stay tuned, and
always root for Team Web!
It is sometimes surprising to me to see what kind of use cases HTML has a
dedicated element for. Something that comes to mind is
<output>,
a container element into which a site or app can inject the results of a
calculation or the outcome of a user action. For another use case that is
arguably more common and which is also the topic of this blog post, HTML has
nothing specific to offer:
footnotes.
Despite several
proposals
to deal with footnotes at the language level,
HTML 3.0 Draft was the last version of
HTML that offered the FN
element. It was designed for footnotes, and when practical, footnotes were to be
rendered as pop-up notes. You were supposed to use the element as in the code
sample below (the inconsistent character casing sic).
<DL> <DT>Hamlet:</DT> <DD> You should not have believed me, for virtue cannot so <ahref="#fn1">inoculate</a> our old stock but we shall <ahref="#fn2">relish of it</a>. I loved you not. </DD>
<DT>Ophelia:</DT> <DD>I was the more deceived.</DD>
<DT>Hamlet:</DT> <DD> Get thee to a nunnery. Why wouldst thou be a breeder of sinners? I am myself <ahref="#fn2">indifferent honest</a> ... </DD> </DL>
<fnid="fn1"><i>inoculate</i> - graft</fn> <fnid="fn2"><i>relish of it</i> - smack of it (our old sinful nature)</fn> <fnid="fn3"><i>indifferent honest</i> - moderately virtuous</fn>
The current HTML Living Standard (snapshot from January 22, 2021) remarks
that HTML does not have a dedicated mechanism for marking up footnotes and
recommends
the following options for footnotes. For short inline annotations, the title
attribute could be used.
<p><b>Customer</b>: Hello! I wish to register a complaint. Hello. Miss?</p> <p> <b>Shopkeeper</b>: <spantitle="Colloquial pronunciation of 'What do you'">Watcha</span> mean, miss? </p>
<p> <b>Customer</b>: Uh, I'm sorry, I have a cold. I wish to make a complaint. </p> <p> <b>Shopkeeper</b>: Sorry, <spantitle="This is, of course, a lie.">we're closing for lunch</span>. </p>
Using title comes with an important downside, though, as the spec rightly
notes.
Unfortunately, relying on the title attribute is currently discouraged as
many user agents do not expose the attribute in an accessible manner as
required by this specification (e.g. requiring a pointing device such as a
mouse to cause a tooltip to appear, which excludes keyboard-only users and
touch-only users, such as anyone with a modern phone or tablet).
For longer annotations, the a element should be used, pointing to an element
later in the document. The convention is that the contents of the link be a
number in square brackets.
<p>Announcer: Number 16: The <i>hand</i>.</p> <p> Interviewer: Good evening. I have with me in the studio tonight Mr Norman St John Polevaulter, who for the past few years has been contradicting people. Mr Polevaulter, why <em>do</em> you contradict people? </p>
<p> Norman: I don't. <sup><ahref="#fn1"id="r1">[1]</a></sup> </p> <p>Interviewer: You told me you did! ...</p>
<section> <pid="fn1"> <ahref="#r1">[1]</a> This is, naturally, a lie, but paradoxically if it were true he could not say so without contradicting the interviewer and thus making it false. </p> </section>
This approach is what most folks use today, for example,
Alex Russell
or the
HTML export
of Google Docs documents.
The other day, I came across a
tweet by
Michael Scharnagl, whose website and Twitter handle
are aptly named Just Markup and who runs a Twitter campaign this year called
#HTMLElementInATweet:
Day 22: <ruby>
Represents small annotations
ℹ️ The term ruby originated as a unit of measurement used by typesetters, representing the smallest size that text can be printed on newsprint while remaining legible.
I had heard about
ruby in the
past, but it was one of these elements that I tend to look up and forget
immediately. This time, for some reason, I looked closer and even consulted the
spec.
The ruby element allows one or more spans of phrasing content to be marked
with ruby annotations. Ruby annotations are short runs of text presented
alongside base text, primarily used in East Asian typography as a guide for
pronunciation or to include other annotations. In Japanese, this form of
typography is also known as furigana.
The rt element marks the ruby text component of a ruby annotation. When it
is the child of a ruby element, it doesn't represent anything itself, but
the ruby element uses it as part of determining what it represents.
The MDN docs
describe the ruby element as follows.
The HTML <ruby> element represents small annotations that are rendered
above, below, or next to base text, usually used for showing the pronunciation
of East Asian characters. It can also be used for annotating other kinds of
text, but this usage is less common.
The markup is straightforward, all you need are
ruby for the
footnote, and
rt for the
footnote text. I like that the footnote is just part of the flow text, so I do
not need to mentally switch context when writing. I also do not have to manually
number my footnotes and come up with and remember the value of ids. Another
small advantage is that footnotes are not part of copied text, so when you copy
content from my site, you do not end up with "text [2] like this". The snippet
below shows the markup of a footnote.
<bodytabindex="0"> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consectetur dictum fermentum. Vivamus non fringilla dolor, in scelerisque massa. Quisque mattis elit quam, eu hendrerit diam ultricies ut. Nunc sit amet velit posuere, malesuada diam in, congue diam. Integer quis venenatis velit. Donec quis nunc <rubytabindex="0" >vel purus<rt >Lorem ipsum dolor sit amet, consectetur adipiscing elit. </rt></ruby > maximus dictum. Sed nec tempus odio. Vestibulum et lobortis ante. Duis blandit pulvinar lectus non sollicitudin. Nulla non imperdiet diam. Fusce varius ultricies sapien id pretium. Praesent ut pellentesque massa. Nunc eu tellus hendrerit risus maximus porta. Maecenas in molestie erat. </p> </body>
The CSS to make the automatic footnote numbering work is based on a
CSS counter.
The rt is styled in a way that it is not displayed by default, and only gets
shown when the ruby's :after, which holds the footnote number, is focused.
For this to function properly, it is important to make the <ruby> element
focusable by setting
tabindex="0".
On mobile devices, the body needs to be focusable as well, so the footnote can
be closed again by clicking/tapping anywhere in the page. The rt element can
contain
phrasing content,
so links and images are all fine. Another thing to remember is to make sure the
rt element remains visible on :hover, so links can be clicked even when the
ruby element loses focus. I have moved the CSS display value of rt into a
CSS custom property, so I could easily play with different values. The CSS below
is all it takes to make the footnotes work.
/* Behavior */
/* Set up the footnote counter and display style. */ body{ counter-reset: footnotes; }
/* Make footnote text appear as `inline-block`. */ ruby{ --footnote-display: inline-block; }
/* Display the actual footnote [1]. */ ruby:after{ counter-increment: footnotes; /* The footnote is separated with a thin space. 🤓 */ content:' ['counter(footnotes)']'; }
/* Remove the focus ring. */ ruby:focus{ outline: none; }
/* Display the footnote text. */ ruby:focus rt{ display:var(--footnote-display); }
/* Hide footnote text by default. */ rt{ display: none; }
/** * Make sure the footnote text remains visible, * so contained links can be clicked. */ rt:hover{ display:var(--footnote-display); }
The following CSS snippet determines the look and feel of the footnotes.
Something I could not get to work (yet) is to make the rt's CSS position to
be absolute. I got the best results so far by making the rt an inline block
by setting the CSS property --footnote-display: inline-block. I am well aware
of ruby-align
and
ruby-position.
The former does not have great browser support at the moment but seems relevant,
and the latter seems to have no effect when I change the display value of rt
to anything other than the UA stylesheet default, which is block. If you
manage to get it to work such that footnote texts open inline, floating right
under the footnote and not affecting the surrounding paragraph text, your help
would be very welcome. I also still need to look into supporting printable
footnotes. If you are interested, you can reach me and
discuss this idea on Twitter.
I have enabled ruby footnotes right on my blog , but you can
also play with a standalone demo on Glitch
and remix its
source code.
⚠️ Please note that this is not production ready. Support seems decent on Blink/WebKit-based
browsers, but not so great on Gecko-based
browsers like Firefox. I have opened an Issue
with the CSS Working Group to hear their opinion on the idea.
The "standards nerd and technology enthusiast"
Terence Eden proposed to use details in a
blog post titled
A (terrible?) way to do footnotes in HTML.
Next, Peter-Paul Koch, web developer,
consultant, and trainer, runs a side project named
The Thidrekssaga and footnotes
where for the current iteration of the site
he just notes that his "implementation of footnotes is mostly shit". If you
have yet another approach apart from what is listed here and above, please
reach out
and I am happy to add it. And as I wrote before, I am looking for help from CSS
experts to make rt positioned absolutely. Sorry for the nerd-snipe.
The post assumes you already have an Xcode project either created
manually
or via the
converter script
and that you use Swift.
Here is an
example build script
for one of my extensions for reference.
Some of these steps may improve or change over time for new versions of Xcode; this guide was written for Version 12.0 (12A7209).
Caveat: this is my first time interacting with Xcode, so if any of the steps do not make sense, thanks for
correcting me.
Change the bundle identifier of the extension from com.example.foo-Extension to
com.example.foo.Extension (that is, replace the '-' with a '.') and reflect the change in
ViewController.swift. For some reason this is necessary.