3

I have two inline elements and I want to change the order of these elements without changing the HTML code. It's possible to do this with CSS only? I know how to change order with flex and grid etc. but these are only for block elements and I am curious if this can be done with inline elements also

*, *::after, *::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
div {
  max-width: 300px;
  border: 2px solid red;
  margin: 2rem;
  padding: 1rem;
}
.red {
  color: red;
}
h1 {
}
h1:last-of-type {
  margin-top: 3rem;
}
span {
  border: 2px solid blue;
}
<div>
  <h1>
    <span>Lorem ipsum sit dolores</span>
    <span class='red'>EKP itd.</span>
  </h1>
  <!-- I need this without changing html -->
  <h1>
    <span class='red'>EKP itd.</span>
    <span>Lorem ipsum sit dolores</span>
  </h1>
</div>
Roy
  • 7,811
  • 4
  • 24
  • 47
Freestyle09
  • 4,894
  • 8
  • 52
  • 83
  • is the text always the same for the red part? If the width is fixed there are some CSS only solution – Temani Afif Sep 15 '21 at 08:54
  • Both text are dynamic – Freestyle09 Sep 15 '21 at 08:56
  • Does this answer your question? [Switching the order of block elements with CSS](https://stackoverflow.com/questions/7425665/switching-the-order-of-block-elements-with-css) – Sam Dean Sep 15 '21 at 08:56
  • 2
    @SamDean it's about inline here not block – Temani Afif Sep 15 '21 at 08:57
  • How specific is the new order? If it's simply reversed then I believe it should be possible, however if you want to select positions for each item, you may have to resort to flex layout. – DBS Sep 15 '21 at 08:57
  • @TemaniAfif the same code works. From the top answer on that question i changed the divs to spans and the flex-flow from col to row and it still works https://jsfiddle.net/q8xamwbj/1/ – Sam Dean Sep 15 '21 at 09:00
  • 2
    @SamDean no it doesn't, we have *inline* elements that wrap based on the text length. Try to apply your code to the OP question, it won't work. Div or span make no difference in a flexbox layout because will get blockified by default – Temani Afif Sep 15 '21 at 09:01
  • @TemaniAfif You can post the solution with fixed width also – Freestyle09 Sep 15 '21 at 09:06
  • @TemaniAfif Sorry I'm clearly missing how this doesn't work. Here is OP's exact code with just 2 id's added and it seems to work exactly as they want https://jsfiddle.net/q8xamwbj/5/ – Sam Dean Sep 15 '21 at 09:10
  • @SamDean it's not the *exact* code of the OP, keep the same styles added by the OP and see the result – Temani Afif Sep 15 '21 at 09:13
  • @SamDean Just make your browser window smaller and make elements wrap. They wrap like a blocks - not inline. – Jax-p Sep 15 '21 at 09:15
  • Ah thanks, I understand now. Delete all my comments now as not relevant? – Sam Dean Sep 15 '21 at 09:17

3 Answers3

2

if the width is fixed you can rely on text-indent and position:absolute

h1 {
  position:relative;
  text-indent:122px;
}

.red {
  color: red;
  position:absolute;
  top:0;
  left:0;
  text-indent:0;
}
span {
  outline: 2px solid blue;
}
*, *::after, *::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
div {
  max-width: 300px;
  border: 2px solid red;
  margin: 2rem;
  padding: 1rem;
}
<div>
  <h1>
    <span>Lorem ipsum sit dolores</span>
    <span class='red'>EKP itd.</span>
  </h1>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Technically this does make the red `span` have `display: block`, but it's probably the closest approach you can get. – DBS Sep 15 '21 at 09:15
  • @DBS that's why I asked if the width of the text is always the same or not and I considered the fact that a small text will not wrap since it's small after all. – Temani Afif Sep 15 '21 at 09:19
1

Well, with CSS only you can fiddle about with pseudo elements and get the required effect - but it's a bit hacky because it requires whoever is changing the short string to also change it in the CSS (e.g. with a CSS variable).

*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

div {
  max-width: 300px;
  border: 2px solid red;
  margin: 2rem;
  padding: 1rem;
}

.red {
  color: transparent;
  position: absolute;
  left: 0;
  top: -2px;
  /* to account for box sizing and border */
  z-index: 1;
  /* incase this is e.g. clickable */
  border: none;
}

h1 {
  position: relative;
}

span:nth-child(1) {
  border: 2px solid blue;
}

span:nth-child(1)::before,
span:nth-child(1)::after {
  content: 'EKP itd.';
}

span:nth-child(1)::before,
span:nth-child(1)::after {
  color: red;
}

span:nth-child(1)::after {
  color: transparent;
  padding: 1px 1px 0 1px;
  background-image: linear-gradient(to left, blue 0 2px, transparent 2px 100%);
  position: absolute;
  top: 0;
  left: 0;
}
<div>
  <h1>
    <span>Lorem ipsum sit dolores</span>
    <span class='red'>EKP itd.</span>
  </h1>
</div>
A Haworth
  • 30,908
  • 4
  • 11
  • 14
-5

If not by CSS, then you can do it with JavaScript

const container = document.querySelector("div h1");
container.append(container.querySelector("span"))
*, *::after, *::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
div {
  max-width: 300px;
  border: 2px solid red;
  margin: 2rem;
  padding: 1rem;
}
.red {
  color: red;
}
h1 {
}
h1:last-of-type {
  margin-top: 3rem;
}
span {
  border: 2px solid blue;
}
<div>
  <h1>
    <span>Lorem ipsum sit dolores</span>
    <span class='red'>EKP itd.</span>
  </h1>
  <!-- I need this without changing html -->
  <h1>
    <span class='red'>EKP itd.</span>
    <span>Lorem ipsum sit dolores</span>
  </h1>
</div>
mplungjan
  • 169,008
  • 28
  • 173
  • 236