Simply earlier than we wrapped up 2025, I noticed this proposal for :close to(), a pseudo-class that may match if the pointer have been to go close to the aspect. By how a lot? Effectively, that may depend upon the worth of the <size> argument offered. Thomas Walichiewicz, who proposed :close to(), means that it really works like this:
button:close to(3rem) {
/* Pointer is inside 3rem of the button */
}
For these questioning, sure, we will use the Pythagorean theorem to measure the straight-line distance between two parts utilizing JavaScript (“Euclidean distance” is the mathematical time period), so I think about that that’s what could be used behind the scenes right here. I’ve some use instances to share with you, however the demos will solely be simulating :close to() because it’s clearly not supported in any internet browser. Lets dig in?
Visible results
With out query, :close to() could possibly be used for a near-infinite (sorry) variety of visible results:
div {
/* Div is wow */
&:close to(3rem) {
/* Div be wowzer */
}
&:close to(1rem) {
/* Div be woahhhh */
}
}
Dim parts till :close to()
To cut back visible litter, you may need to dim sure parts till customers are close to them. :close to() could possibly be more practical than :hover on this situation as a result of customers might have hassle interacting with the parts if they’ve restricted visibility, and so with the ability to set off them “earlier” might compensate for that to a point. Nevertheless, now we have to make sure accessible coloration distinction, so I’m undecided how helpful :close to() will be on this state of affairs.
button:not(:close to(3rem)) {
opacity: 70%; /* Or...one thing */
}
Conceal parts till :close to()
Along with dimming parts, we might additionally conceal parts (so long as they’re not essential, that’s). This, I feel, is a greater use case for :close to(), as we wouldn’t have to fret about coloration distinction, though it does include a unique accessibility problem.
So, you realize whenever you hover over a picture and a share button seems? Is smart, proper? As a result of we don’t need the picture to be obscured, so it’s hidden initially. It’s not optimum by way of UX, but it surely’s nonetheless a sample that persons are aware of, like on Pinterest for instance.
And right here’s how :close to() can improve it. Individuals know or suspect that the button’s there, proper? In all probability within the bottom-right nook? They know roughly the place to click on, however don’t know precisely the place, as they don’t know the dimensions or offset of the button. Effectively, displaying the button when :close to() signifies that they don’t should hover so precisely to make the button seem. This situation is fairly just like the one above, maybe with completely different causes for the decreased visibility.
Nevertheless, we want this button to be accessible (hoverable, focusable, and find-in-pageable). For that to occur, we will’t use:
show: hidden(not hoverable, focusable, or find-in-pageable)visibility: hidden(additionally not hoverable, focusable, or find-in-page-able)opacity: 0(there’s no approach to present it as soon as it’s been discovered by find-in-page)
That leaves us with content-visibility: hidden, however the issue with hiding content material utilizing content-visibility: hidden (or parts with show: none) is that they actually disappear, and you’ll’t be close to what merely isn’t there. Because of this we have to reserve house for it, even when we don’t know how a lot house.
Now, :close to() isn’t supported in any internet browser, so within the demo under, I’ve wrapped the button in a container with 3rem of padding, and whereas that container is being :hovered, the button is proven. This will increase the dimensions of the hoverable area (which I’ve made pink, as a way to see it) as a substitute of the particular button. It primarily simulates button:close to(3rem).
However how will we conceal one thing whereas reserving the house?
First, we declare contain-intrinsic-size: auto none on the hidden goal. This ensures that it stays a selected dimension at the same time as one thing adjustments (on this case, at the same time as its content material is hidden). You’ll be able to specify a <size> for both worth, however on this case auto means regardless of the rendered dimension was. none, which is a required fallback worth, may also be a <size>, however we don’t want that in any respect, therefore “none.”
The issue is, the rendered dimension “was” nothing, as a result of the button is content-visibility: hidden, keep in mind? Which means we have to render it if just for a single millisecond, and that’s what this animation does:
<div id="picture">
<div id="simulate-near">
<button hidden="until-found">Share</button>
</div>
</div>
@keyframes show-content {
from {
content-visibility: seen;
}
}
button {
/* Conceal it by default */
&:not([hidden="until-found"]) {
content-visibility: hidden;
}
/* However make it seen for 1ms */
animation: 1ms show-content;
/* Save the dimensions whereas seen */
contain-intrinsic-size: auto none;
}
Word that if the button has the hidden=until-found attribute-value, which is what makes it focusable and find-in-page-able, content-visibility: hidden isn’t declared as a result of hidden=until-found does that mechanically. Both approach, the animation declares content-visibility: seen for 1ms whereas contain-intrinsic-size: auto none captures its dimension and reserves the house, enabling us to hover it even when it’s not seen.
Now that you just perceive the way it works, right here’s the total code (once more, simulated, as a result of :close to() isn’t supported but):
<div id="picture">
<div id="simulate-near">
<button hidden="until-found">Share</button>
</div>
</div>
@keyframes show-content {
from {
content-visibility: seen;
}
}
#simulate-near {
/* As an alternative of :close to(3rem) */
padding: 3rem;
button {
/* Unset any kinds */
border: unset;
background: unset;
/* However embody size-related kinds */
padding: 1rem;
/* Conceal it by default */
&:not([hidden="until-found"]) {
content-visibility: hidden;
}
/* However make it seen for 1ms */
animation: 1ms show-content;
/* Save the dimensions whereas seen */
contain-intrinsic-size: auto none;
}
&:the place(:hover, :has(:focus-visible)) button {
coloration: white;
background: black;
content-visibility: seen;
}
}
In the event you’re questioning why we’re unsetting border and background, it’s as a result of content-visibility: hidden solely hides the content material, not the aspect itself, however we’ve included padding right here as a result of that impacts the dimensions that we’re making an attempt to render n’ keep in mind. After that we merely apply these kinds in addition to content-visibility: seen to the button when the the wrapper is :hovered or :has(:focus-visible).
And right here’s the identical factor however with the unsupported :close to():
<div id="picture">
<button hidden="until-found">Share</button>
</div>
@keyframes show-content {
from {
content-visibility: seen;
}
}
button {
/* Unset any kinds */
border: unset;
background: unset;
/* However embody size-related kinds */
padding: 1rem;
/* Conceal it by default */
&:not([hidden="until-found"]) {
content-visibility: hidden;
}
/* However make it seen for 1ms */
animation: 1ms show-content;
/* Save the dimensions whereas seen */
contain-intrinsic-size: auto none;
&:the place(:close to(3rem), :hover, :focus-visible) {
coloration: white;
background: black;
content-visibility: seen;
}
}
Briefly, :close to() allows us to do what the simulated method does however with out the additional markup and artistic selectors, and if there are any accessibility wants, now we have that animation/contain-intrinsic-size trick.
Prefetch/prerender when close to
I’m not suggesting that there’s a approach to prefetch/prerender utilizing :close to() and even that the performance of :close to() needs to be prolonged, however somewhat that the Hypothesis Guidelines API might leverage its underlying performance. The Hypothesis Guidelines API already makes use of mousedown, touchstart, pointer path and velocity, viewport presence, and scroll pauses as alerts to start prefetching/prerendering the linked useful resource, so why not when close to?
In reality, I feel “close to” as an idea could possibly be utilized for lots greater than :close to(), and ought to be contemplating that customized hit-testing utilizing pointermove has a excessive efficiency price and implementation complexity (as Thomas factors out). Let’s have a look at one other instance.
Enhance curiosity invoker interactions
When interacting with hover-triggered overlays, there’s danger of unintentionally transferring the pointer away from the set off or goal. The Curiosity Invoker API, which facilitates hover-triggered interactions, makes use of the interest-show-delay and interest-hide-delay CSS properties to forestall unintentional activations and deactivations respectively, however from a person expertise perspective, something involving delays and time-sensitivity simply isn’t enjoyable.
A few examples:
- The pointer falling into the hole between the curiosity set off (e.g., a hyperlink or button) and curiosity goal (e.g., a popover)
- The pointer overshooting the bounds of the curiosity goal when making an attempt to work together with parts close to the sting of it
Subsequently, as a substitute of (or along with) present and conceal delays, the Curiosity Invoker API might leverage the idea of “close to” to make sure that overlays don’t disappear resulting from mis-interaction. This could possibly be configurable with a CSS property (e.g., near-radius: 3rem or simply close to: 3rem), which in contrast to :close to() would invoke performance (curiosity and loseinterest JavaScript occasions, on this case).
One other use-case, prompt by Thomas in his proposal: displaying a “drag to reorder” trace whereas hovering close to a draggable aspect. It is a terrific use-case as a result of displaying tooltips even just some milliseconds earlier would possible scale back activity time.
Sadly, you’d have a tough time (I feel?) simulating these ones with legitimate HTML, largely as a result of <a>s and <button>s can solely comprise sure parts.
Downsides to :close to()
A possible draw back is that :close to() might result in a big enhance in builders lazily hiding issues to cut back visible litter in situations the place higher UI design would’ve been the best name, or rising visible litter (with pointless icons, for instance) as a result of it may be hidden extra conditionally.
Different potential abuses embody heatmapping, fingerprinting, and aggressive promoting patterns. It is also utilized in ways in which would negatively impression efficiency. Thomas’s proposal does an exquisite job of declaring these abuses and the methods through which :close to() could possibly be applied to thwart them.
:close to() accessibility considerations
:close to() shouldn’t suggest :hover or :focus/:focus-visible. I feel that a lot is apparent whenever you actually give it some thought, however I can nonetheless see the strains getting crossed. A very good query to ask earlier than utilizing :close to() is: “Are we being preemptive or presumptive?” Preemptive will be good however presumptive would at all times be unhealthy, as we by no means need customers to assume that they’re hovering or specializing in an interactive aspect after they’re not (or not but). That is talked about in numerous elements of the Net Content material Accessibility Pointers, however most notably in Success Criterion 2.4.7: Focus Seen (Degree AA).
Equally, Success Criterion 2.5.8: Goal Measurement (Degree AA) states that interactive parts smaller than 24x24px will need to have further spacing round them, calculated as 24px - goal width/24px - goal peak, however whether or not or not the worth of :close to() would issue into that could be a bit ambiguous.
In conclusion
There’s heaps to consider right here, however finally I’d like to see this applied as Thomas has proposed it. Having mentioned that, the WCAG steering should be rock-solid earlier than any implementation begins, particularly contemplating that we will already accomplish what :close to() would do (albeit with extra markup and perhaps some CSS trickery).
And once more, I feel we should always entertain the thought of “close to” as an idea, the place the underlying performance could possibly be leveraged by the Hypothesis Guidelines API and Curiosity Invoker API (the latter with a CSS property like near-radius).
Your ideas, please!
Doubtlessly Coming to a Browser :close to() You initially printed on CSS-Methods, which is a part of the DigitalOcean household. You need to get the e-newsletter.
