How do you makes "emoji as a letter" accessible?

I have some logo text that includes the word "đź’ˇdea" - what would be the best way to write this?
18 Replies
13eck
13eck•3mo ago
My initial thought is to have the emoji in a ::before pseudo element so it’s not read by screen readers. Then have a hidden span with the I so it’s not seen by the eyes but a screen reader can read it
<p><span class=“hidden”>I</span>dea</p>
<p><span class=“hidden”>I</span>dea</p>
-# (Note the lack of space between I and dea)
Lofty!
Lofty!OP•3mo ago
Sounds kinda... silly but how would I hide it but ensure that the text remains centered(-ish)? Here's the current component that I have:
<section>
<p><span>I</span>deas go on pages,<br />not in bins.</p>
</section>

<style>
section {
max-width: var(--prose-width);
margin: 0 auto;
padding: 2rem 0.75rem 0 0.75rem;
}

p {
--font-hero-logo: clamp(1.56rem, 1.122rem + 2.19vw, 3.75rem);
font: var(--font-hero-logo) aclonica;
text-align: center;
}

span {
/* dunno what to put here */

&::before {
content: "đź’ˇ";
}
}
</style>
<section>
<p><span>I</span>deas go on pages,<br />not in bins.</p>
</section>

<style>
section {
max-width: var(--prose-width);
margin: 0 auto;
padding: 2rem 0.75rem 0 0.75rem;
}

p {
--font-hero-logo: clamp(1.56rem, 1.122rem + 2.19vw, 3.75rem);
font: var(--font-hero-logo) aclonica;
text-align: center;
}

span {
/* dunno what to put here */

&::before {
content: "đź’ˇ";
}
}
</style>
13eck
13eck•3mo ago
Something like this:
<p>
<span class="bulb">I</span><span>dea</span>.
</p>
<p>
<span class="bulb">I</span><span>dea</span>.
</p>
.bulb {
visibility: hidden;
}

.bulb + span::before {
content: "đź’ˇ";
}
.bulb {
visibility: hidden;
}

.bulb + span::before {
content: "đź’ˇ";
}
Made a codepen but on my phone so codepen isn’t logged in so I can’t share the pen
Lofty!
Lofty!OP•3mo ago
all good, got the idea!
Chris Bolson
Chris Bolson•3mo ago
Would a word that has it's letters split up by spans be accessible? Wouldn't a screen reader see that as 2 separate entities?
caldane
caldane•3mo ago
This is a little fiddley. It is consistent across a single font-family, but if you changed the font-family you would need to change the ch value. The advantage of this method would be that a screen reader would read the word properly.
<p class="inline">
đź’ˇ<span class="bulb">Idea</span>
</p>
<p class="inline">
đź’ˇ<span class="bulb">Idea</span>
</p>
p.inline {
display: flex;
align-items: end;
font-size: 1.3rem;
}

span.bulb {
display: flex;
justify-content: end;
width: 2.8ch;
overflow: hidden;
}
p.inline {
display: flex;
align-items: end;
font-size: 1.3rem;
}

span.bulb {
display: flex;
justify-content: end;
width: 2.8ch;
overflow: hidden;
}
Also if you didn't want the screen reader to read the emoji you could put it in a before element instead.
<p class="inline">
<span class="bulb">Idea</span>
</p>
<p class="inline">
<span class="bulb">Idea</span>
</p>
p.inline {
display: flex;
align-items: end;
font-size: 1.3rem;

&::before {
content: "đź’ˇ"
}
}

span.bulb {
display: flex;
justify-content: end;
width: 2.8ch;
overflow: hidden;
}
p.inline {
display: flex;
align-items: end;
font-size: 1.3rem;

&::before {
content: "đź’ˇ"
}
}

span.bulb {
display: flex;
justify-content: end;
width: 2.8ch;
overflow: hidden;
}
Jochem
Jochem•3mo ago
and if you want to keep the lightbulb in the HTML, and not potentially have a ton of classes just because you want a dozen different emoji in your text:
<span style="--content: 'đź’ˇ'">Idea</span>
<span style="--content: 'đź’ˇ'">Idea</span>
span::before {
content: var(--content);
}
span::before {
content: var(--content);
}
any span that doesn't have --content set will just not have a ::before
13eck
13eck•3mo ago
You have a beautiful, beautiful brain
caldane
caldane•3mo ago
You would have to be careful with nested spans and also you do not have a way to "eat" the first character if you put the emoji in the span.
Jochem
Jochem•3mo ago
hmm, but you could adapt using style to set the content to use your version I dislike hardcoding something that should be in HTML in CSS, because now all of a sudden you have to update two files if you just want to change some text, and if that text is in the database, now to update it you have to deploy something new rather than just update a field in a CMS backend
caldane
caldane•3mo ago
Yes with the caveat that nested components (which is super unlikely) would still have --content set.
Jochem
Jochem•3mo ago
you could use this
span.emoji::before {
content: var(--content);
}
span.emoji::before {
content: var(--content);
}
to solve that
caldane
caldane•3mo ago
I do not disagree but it may be a better use case for attr than a custom property
Jochem
Jochem•3mo ago
that could definitely work too
Chris Bolson
Chris Bolson•3mo ago
I came up with something similar using the ::first-letter selector to make the "I" transparent as you can't actually hide a letter using this selector as far as I am aware.
<p><span data-icon="đź’ˇ">Ideas</span> go on pages, not in bins.</p>
<p><span data-icon="đź’ˇ">Ideas</span> go on pages, not in bins.</p>
span[data-icon] {
display: inline-block;
position: relative;
&::first-letter{
color: transparent;
}
&::before {
content: attr(data-icon);
position: absolute;
font-size: inherit;
left: -1.3rem; /* magic number */
}
}
span[data-icon] {
display: inline-block;
position: relative;
&::first-letter{
color: transparent;
}
&::before {
content: attr(data-icon);
position: absolute;
font-size: inherit;
left: -1.3rem; /* magic number */
}
}
The only thing I don't like about it is the magic number to position the icon where the "I" would be. Note, I did just modify it to use a data attribute for the icon as that seemed like a great idea, I originally had it hard-coded as the content.
Jochem
Jochem•3mo ago
you could set the font-size to 0 or something maybe?
caldane
caldane•3mo ago
@Jochem font-size: 0 works well. Just tested in a code pen https://codepen.io/caldane/pen/XWvXLob
<span data-icon="đź’ˇ"><span>Idea</span></span>
<span data-icon="đź’ˇ"><span>Idea</span></span>
The nested spans are still necessary to so you don't end up targeting the emoji with the first-letter selector. @Chris solved this by making it position absolute, but then you have to position the emoji (which was possible with right: 100%). This way doesn't require jumping out of the stacking context, which has some value.
span[data-icon] {
display: flex;
align-items: end;

span {
line-height: 0.9;
&::first-letter {
font-size: 0px;
}
}

&::before {
content: attr(data-icon);
}
}
span[data-icon] {
display: flex;
align-items: end;

span {
line-height: 0.9;
&::first-letter {
font-size: 0px;
}
}

&::before {
content: attr(data-icon);
}
}
The display flex and align-items is to force the text and emoji to have the same lower bounds. The line height is a bit of a hack but it allows for the emoji to look like it is on the same baseline as the text. With everyone's suggestion implemented in this version I find it to be a rather elegant solution to an interesting problem.
caldane
CodePen
Untitled
...
Lofty!
Lofty!OP•3mo ago
oh wow, I come back after a while and.. damn. thanks <3
Want results from more Discord servers?
Add your server