Consider this bar of buttons:
body {text-align: right;}
<button>Save</button>
<button>Cancel</button>
<button>Delete</button>
Now let's say that the last button's content changes:
body {text-align: right;}
<button>Save</button>
<button>Cancel</button>
<button>Click me again to confirm deletion</button>
As you can see, this change in the rightmost button triggered all buttons to its left to move.
To avoid this, I'd like the button's original size to fit the larger one of its two possible contents.
Of course, I can try to "achieve" this in many ways. The simplest and ugliest is to experiment how much width the larger content requires and "hardcode" it:
body {text-align: right;}
#del {display: inline-block; width: 220px;}
<button>Save</button>
<button>Cancel</button>
<button id="del">Delete</button>
However, I consider it a non-solution because it cannot be guaranteed that this width will be the same for everyone else. If someone has a weird font, or uses text magnification, or views the site on mobile, or whatever, then I suppose setting the button's width to a hardcoded value could produce weird results.
Another way, I suppose, would be to (a) Initially put the longer text to the button (b) Get the button's width through JavaScript and save it (c) Put the actual, shorter text to the button and set its width to that value. To my intuition, however, this looks like a horrible hack and overkill.
What is the canonical solution to troubles like this?
I would consider data attribute to add both texts using pseudo elements then control the opacity to hide/show them:
div {
text-align: right;
}
#del {
display: inline-block;
position: relative
}
#del:before {
content: attr(data-text);
position:absolute;
left:0;
right:0;
top:1px; /*there is 1px default padding */
text-align:center;
}
#del:after {
content: attr(data-alt);
opacity:0;
}
#del:hover::before {
opacity:0;
}
#del:hover::after {
opacity:1;
}
<div><button>Save</button><button>Cancel</button><button data-text="Delete" data-alt="Click me again to confirm deletion" id="del"></button></div>
You simply need to know which one will be the wider one to keep it in-flow to define the width and make the other one position:absolute
.
You can also keep the main text inside:
div {
text-align: right;
font-size:14px;
}
#del {
display: inline-block;
position: relative;
}
#del span {
content: attr(data-text);
position:absolute;
left:0;
right:0;
top:1px; /*there is 1px default padding */
text-align:center;
}
#del:after {
content: attr(data-alt);
opacity:0;
}
#del:hover span {
opacity:0;
}
#del:hover::after {
opacity:1;
}
<div><button>Save</button><button>Cancel</button><button data-alt="Click me again to confirm deletion" id="del"><span>Delete</span></button></div>