Assume I have a small component in a web application that represents an expander control, i.e. a header text, an icon to expand / collapse and some content.
A very simple React implementation (pseudo code) could look like this:
const Expander = ({children, title, onExpandToggle, isExpanded}) => (
<div>
<div><span>{title}</span><img src={...} onClick={onExpandToggle} /></div>
{isExpanded && children}
</div>
);
This implementation shows the icon after the title, so the position of the icon is determined by the length of the title.
It could look something like this:
Now assume that there are multiple like this below each other. It becomes messy:
To make this cleaner, all icons should have the same padding from left. The padding should not be fixed but dynamic, so that the longest title determines the position of all icons:
Assuming that I want to keep the expander in its own component, is there a CSS way to achieve my goal?
So far, I haven't tried anything as I don't have a starting point. In WPF I would have used something like SharedSizeGroup
, but this doesn't exist for CSS.
Assuming you'll have a container to your component, you can set display: flex
to the inner container and align-self: flex-end
to your image.
Then wrap your component/s with a div that has display: inline-block
which takes the width of the biggest element inside.
Here's an example:
.container{
display: inline-block;
padding: 3px;
}
.item{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.item .plus{
width: 15px;
height: 15px;
background-image: url("https://cdn1.iconfinder.com/data/icons/mix-color-3/502/Untitled-43-512.png");
background-size: cover;
background-repeat: no-repeat;
align-self: flex-end;
margin-left: 10px;
}
<div class="container">
<div class="item">
<div>Synonyms</div>
<div class="plus"></div>
</div>
<div class="item">
<div>Concept</div>
<div class="plus"></div>
</div>
<div class="item">
<div>Term</div>
<div class="plus"></div>
</div>
</div>
Affecting all the instances without a shared container or fixed width and with CSS alone, is not possible, since there is no way to access a parent element with CSS. Therefore, If you'll have an inner instance (the biggest one) it won't be able to apply it's width to its own parent or any ancestor and it's other children.
If you're after a solution that will set all the instances in the page with the same size without them sharing a container you can achieve it with JS.
Calculate the width of each instance, save the biggest, then set this width for the rest of the instances. In this example I'm also highlighting the biggest item. The items are all around the page and can be inside various divs and displays or without any container.
var biggestWidth = 0;
var biggestItem;
function setWidth() {
$(".item").each(function() {
var currentWidth = $(this).width();
if (currentWidth > biggestWidth) {
biggestWidth = Math.ceil(currentWidth);
biggestItem = $(this);
}
});
$(".item").width(biggestWidth);
biggestItem.addClass("biggest");
}
$(setWidth());
section {
width: 40%;
float: left;
border: 1px solid black;
border-radius: 3px;
margin: 10px;
padding: 10px;
}
.s1 {
background-color: #e5e5e5;
display: table;
}
.item {
display: inline-block;
clear: both;
float: left;
}
.txt {
float: left;
display: inline-block;
}
.plus {
width: 15px;
height: 15px;
background-image: url("https://cdn1.iconfinder.com/data/icons/mix-color-3/502/Untitled-43-512.png");
background-size: cover;
margin-left: 10px;
float: right;
}
.shift{
margin-left: 30%;
}
.clear{
clear: both;
}
.biggest{
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="s1">
<div class="item">
<div class="txt">Synonyms</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Concept</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Term</div>
<div class="plus"></div>
</div>
</section>
<section>
<div class="item">
<div class="txt">Synonyms</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Concept</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Term</div>
<div class="plus"></div>
</div>
</section>
<section>
<div class="item">
<div class="txt">Synonyms - Long</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Concept</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Term</div>
<div class="plus"></div>
</div>
</section>
<div class="item">
<div class="txt">Synonyms</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Concept</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Term</div>
<div class="plus"></div>
</div>
<div class="clear"></div>
<div class="shift">
<div class="item">
<div class="txt">Synonyms</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">Concept</div>
<div class="plus"></div>
</div>
<div class="item">
<div class="txt">The bigget item is here</div>
<div class="plus"></div>
</div>
</div>