When a CSS transform is applied to an element, like
it seems that element’s position property is forced to relative. This side effect introduces quirky behaviour, when you depend on the position being static.
Here’s an explanation of what happens. Luckily there’s also a simple solution to this problem.
A child outgrown its parent
Suppose we have an article element that contains a link:
To expand the area of the link responding to hovering and clicking/tapping to the whole article we can define a CSS pseudo-element:
This pseudo-element behaves like a child element of the <a>-tag in the DOM. By positioning it absolute and setting top, left, right and bottom to 0, it takes up the space of its nearest ancestor that is a positioned element. We want that ancestor to be our <article>.
Events received by the large pseudo-element now bubble up to its small parent. Below is an example that shows a box without and with mouseover.
Now suppose we styled the anchor element as a button and we want to react on hovering over the article by making the button bigger.
Can you predict what will happen? Check this CodePen.
It turns out that if you hover over the article but not the anchor the button starts to flicker. What happens is that when a transform is applied, the transformation must be relative to some basic state. Therefor its position is secretly changed to relative. Now the pseudo-element that was positioned relative to the article is suddenly positioned relative to the button. In effect the pseudo-element shrinks to the size of the button. This ends the hovering and as a consequence the transform and the position property of the button reverts to static. And then everything starts over again.
So when a transform is applied to a static element, its position property is changed as a side effect. And as happens more often, side effects cause bugs, or quirky behaviour.
To prevent this I guess transformable objects should be explicitly positioned elements. However, this restriction is not in the W3 specification.
There is a simple solution to this problem. We need to change the HTML structure a bit and place the button inside the anchor element, as a child element:
Apply the transform to the button when the anchor, which is now the parent of the button, is hovered. This leaves the position property of the anchor alone, and prevents the pseudo-element of the anchor to shrink.
Here’s a final CodePen to see this soluton at work.
The order of definition of pseudo-classes for the anchor tag is crucial.
In Firefox I noted that if you define :visited after :hover, you may not get the style you expect when hovering over an <a> element. That’s logical, if you think of it. But it can be confusing because the Inspector seems to ignore the style for :visited, leaving us clueless.
Looking for clues I checked Chrome too. The problem did not occur there, but that was because I hadn’t visited the page the link was pointing to yet.
Just a note on the way I currently like to set up development of a Gutenberg block. Basically these are the steps mentioned in the WordPress block editor handbook, that uses the @wordpress/package to work with the webpack and Babel libraries, without too much hassle.
Assumed Node.js and npm are installed, enter
Next install the WordPress packages and all their dependencies. This may take a while.
With the WordPress Gutenberg editor it is easy to create full-width blocks. If it isn’t already, we can activate this feature for the theme with the following line in functions.php:
Combined with Group blocks, this allows us to create a full-width section where the inner content aligns with the content in blocks with regular width. The full-width containers can be used to show an alternative background color or image. Very useful for headers, footers, navigation bars etc.
The group block is present in Gutenberg Core since WordPress 5.3.
Step by step
Create a Group block that will serve as our container.
Make the block full-width.
In the Advanced panel of the Inspector controls, set an additional CSS class, for example my-full-width-container.
The group block very conveniently adds an inner container with class .wp-block-group__inner-container. Match margins and padding of the inner container with those of the regular content blocks, for example: