0

I am fairly new to React. I am also new to asking questions on this forum.

I have a pretty basic two column layout and I am trying to dynamically set the image size in the RH column to match the height of the text content of the LH column.

I have figured out I can't get the scrollHeight value of the ref'd element until the page is rendered but I don't want to render the page until I know the scrollHeight value to render the image...and around in circles I go.

I can get the ref'd value if I put a console.log inside a useEffect() but I don't know to adapt this to help me solve the specific problem.

Can anyone help with a solution or another method to achieve this same idea?

const tickList = useRef();


useEffect(() => {
  console.log(tickList);
}, [])


<div className='ticklist-container' ref={tickList}>
        <TickCrossList items={tickListItems} />
      </div>


<div className='image-container p-1 flex flex-center'>
        <img
          src={imageUrl}
          alt={imageAltText}
          style={{ width: tickList.current.scrollHeight * 1.77 }}
        />
      </div>
BenDev
  • 1
  • 3
  • Why can't they start out the same size VIA CSS? What would prompt the text size to change dynamically? – AttemptedMastery Apr 15 '22 at 03:49
  • @AttemptedMastery The height of the content on the LH column is dynamic. I am passing the 'items' array via props which contains objects to map a list. If I add some items to the list I want the image to scale dynamically to be basically the same height as the list, while preserving the 16:9 ratio for the image. – BenDev Apr 15 '22 at 04:11
  • 1
    I really may be oversimplifying this but again, scaling an image relevant to it's siblings is a common feature amongst CSS layout methodologies. Flexbox would work ideally for this. Check this link to see if it fits your use-case: https://stackoverflow.com/questions/21103622/auto-resize-image-in-css-flexbox-layout-and-keeping-aspect-ratio – AttemptedMastery Apr 15 '22 at 04:17
  • @AttemptedMastery That's fine mate, I am totally open to other non React solutions as it's quite possible there's something I've missed with the CSS. However, I am not sure how the info in the link can assist me - seems like if I use FlexBox the size of the image controls the size of the left hand column, not the other way around? – BenDev Apr 15 '22 at 04:33
  • @AttemptedMastery In fact, I can already see that the image has pushed the text content left so that instead of getting an even 50-50 ratio of the columns, it's more like 30-70. – BenDev Apr 15 '22 at 04:37

1 Answers1

1

I believe this is, at core, an XY problem. You're asking how to technically achieve a nearly impossible task (1) when you're actually trying to answer another question: how to make some text and an image look good side by side (2) (which, by and large, is not an actual coding problem - it's a graphical design problem).

Most notably, you're not providing either the text or the image, so you're asking for a general solution, which would work in all cases. That solution doesn't exist. Picture how the result would look if the text was 1 letter long and how it would look if it was 2 pages long.

Last, but not least, the problem is not strictly related to React. In general, you should ask yourself:

  • is this achievable in DOM (HTML + CSS + JS)?
  • does it need JS?
  • once you answer both of the above with "yes", and you know how the output should look like, the React part is generally easy.

In more detail...

(1). When you're changing the image size, provided you maintain its ratio, you're going to affect the paragraph's width, causing it to re-wrap, changing its height, potentially creating a loop. In many cases, you'd need to re-run the script multiple times until the text no longer re-wraps when adjusting the image height.

  1. In some cases, depending on the amount of text, a solution doesn't even exist.
  2. In other cases, the script will jump between two positions, basically two different numbers of text rows, each resizing the image, causing the text to jump to the other number of rows, causing the whole thing to tremble indefinitely. I've actually seen this quite a few times, on production websites. The general fix is to record each resizing step and, should the script get any of the previous values, kill it. An ugly fix for an ugly bug.
  3. And, in some other cases, you might find multiple possible "solutions". Which one should the script pick?

Picture all this in the context of resize events (a user flipping their tablet from landscape to portrait and back) and you got a recipe for disaster, UX-wise.

Not to mention browsers nowadays allow users to override font-size or font-family, giving control over readability. How would your script cope with this change?


(2) How this problem is typically solved.

There are a few distinct considerations:

  • the image needs to have a minimum size, at which it conveys whatever message it carries. It needs to remain "readable" at all times. Not too small, but not too large, either. It has to be in balance with the amount of text.
  • if there's too much text, you either make its box scrollable (depending on case) or you crop the sides of the image (if image is "croppable" - from a graphical POV).
  • the text needs to remain readable (with ease) at all times (lines shouldn't be too long or too short)
  • typically, you want to roughly determine a ratio between the minimal image size and a paragraph width good for readability and set a consistent ratio (throughout the whole app/website) between the two (design consistency pays off in how your website is perceived as a whole - it provides rhythm and an overall feeling of confidence and reliability, when done right). Go with 1:1, 2:1, 3:1, 1:2, 1:3, based on paragraph length and readability. Another good ratio is 1:1.618 (the golden ratio - it's pleasing to the eye, without an exact explanation - debugging humans is particularly difficult)
  • a typical solution is to wrap the paragraph into a slightly bigger, visible box, with a slightly different background or border color. This gives you significantly more flexibility in matching the image height. See the examples below.
  • below a particular container width, you want the two elements (the image and the text box) to wrap, so they both remain readable and attractive (e.g: responsiveness)

A few bad examples you probably want to avoid (but you're currently asking for), followed by a possible answer to the Y problem:

.container {
  display: flex;
  max-width: 600px;
  margin: 0 auto;
  margin-top: 1rem;
  justify-content: space-between
}

.proper img {
  width: 50%;
}
.proper div {
  background-color: #F5f5f5;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2em;
}
.proper.two div {
  background-color: transparent;
  border: solid #ddd;
  border-width: 1px 0 1px 1px;
}
<div class="container">
  <h3>What you probably don't want</h3>
</div>
<div class="container">
  <div>Spiff up your work with our random beer Lorem Ipsum generator. Beer!</div>
  <img src="https://random-ize.com/lorem-ipsum-generators/beer/suds3.jpg" style="max-width: 528px">
</div>

<div class="container">
  <div>Spiff up your work with our random beer Lorem Ipsum generator. Beer!
  </div>
  <img src="https://random-ize.com/lorem-ipsum-generators/beer/suds3.jpg" style="max-width: 515px">
</div>

<div class="container">
  <div>Spiff up your work with our random beer Lorem Ipsum generator. Beer!
  </div>
  <img src="https://random-ize.com/lorem-ipsum-generators/beer/suds3.jpg" style="height: 1em">
</div>

<div class="container">
  <div>Spiff up your work with our random beer Lorem Ipsum generator. More Beer!
  </div>
  <img src="https://random-ize.com/lorem-ipsum-generators/beer/suds3.jpg" style="height: 2em">
</div>

<div class="container">
  <h3>What you probably want</h3>
</div>
<div class="container proper">
  <div>Spiff up your work with our random beer Lorem Ipsum generator. Beer!</div>
  <img src="https://random-ize.com/lorem-ipsum-generators/beer/suds3.jpg">
</div>
<div class="container proper two">
  <div>Spiff up your work with our random beer Lorem Ipsum generator. Beer!</div>
  <img src="https://random-ize.com/lorem-ipsum-generators/beer/suds3.jpg">
</div>

As a bonus, what golden ratio can do for you:

* {
  box-sizing: border-box;
}
body {
  background-color: #f5f5f5;
  margin: 0;
  padding: 0 2.1rem;
}
.container {
  padding: 2.1rem 0;
  max-width: 500px;
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  align-items: center;
}
.golden-ratio {
  border-radius: .35rem;
  overflow: hidden;
  display: flex;
  justify-content: space-between;
  background-color: white;
  color: #aaa;
  aspect-ratio: 1.618;
  box-shadow: 0 1px 5px 0 rgb(0 0 0 / 10%), 0 2px 2px 0 rgb(0 0 0 / 07%), 0 3px 1px -2px rgb(0 0 0 / 06%)
}
.image-container {
  flex-grow: 1;
  background: #ddd url('https://random-ize.com/lorem-ipsum-generators/beer/suds3.jpg') 100% /cover;
}
.content {
  flex: 0 0 61.8%;
  font-size: 1.5rem;
  font-style: italic;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 10%;
}

@media (max-width: 600px) {
  .golden-ratio {
    flex-direction: column-reverse;
    aspect-ratio: unset;
  }
  .content {
    flex-basis: 50%;
    padding: 3rem;
    font-size: 1.2rem;
  }
  .image-container {
    aspect-ratio: 4.16;
    flex-basis: 50%;
  }
}
<div class="container">
  <div class="golden-ratio">
    <div class="content">Spiff up your work with our random beer Lorem Ipsum generator. Beer!</div>
    <div class="image-container"></div>
  </div>
</div>
a.h.g.
  • 1,429
  • 3
  • 12
  • HI mate, thanks for your answer - it helps ease my mind that I wasn't missing something that would make this a fit-all case. I used your 'typically solved' advice to work out a ratio of the size of the image to the text with percentages and stuff and while it's not the ideal solution I was looking for, it seems as thought the ideal solution doesn't exist. Thanks for taking the time to answer mate, much appreciated. – BenDev Apr 18 '22 at 04:55
  • @BenDev, it would exist if you created it. Can you write down the logical steps a bot would follow so it wouldn't end up in any of the first 4 cases in the first snippet I wrote, regardless of text length and regardless of image size or ratio? So far, in more than 50 years of internet, nobody has. You'd likely become famous. – a.h.g. Apr 19 '22 at 08:27