0

I am displaying information in a card-based layout, but if any title in the card is longer than 41 characters, it doesn't fit into the card.

I thought about using [wordwrap], but all that would do is cause the one specific title to wrap and change the height of that card, affecting the layout of the other cards.

This is the PHP I use to print my results for pagination purposes, so it only prints 9 things at a time.

<div class="row">
<?php
while ($row = mysql_fetch_assoc($rs_result)) {
?>
<div class="col xl4 l4 m12 s12">
<div class="card z-depth-5">
    <div class="card-content">
      <p><? echo $row["title"]; ?></p>
      <p>Category: <? echo $row["category"]; ?></p>
    </div>

</div>
</div>
<?php
};
?>
</div>

How would I go about line breaking every title if even one title is detected as longer than 41 characters?

EDIT: This is the solution I created:

$titlebreak = $row["title"];
if (strlen($titlebreak) >= 40)
    {
        $titlebreak2 = wordwrap($titlebreak, 39, "</p><p>");
    }
    else
    {
        $titlebreak2 = $row["title"] . "<p>&nbsp;</p>\n";
    }
JayMax
  • 113
  • 1
  • 10

2 Answers2

0

I've included 3 possible solutions below - adding manual line breaks as you asked about in your question; a basic but unsatisfactory CSS option and a jQuery solution which in this case is the one I would suggest as the most flexible.

Although a CSS-only solution is usually the preferred way of fixing a layout issue, when it comes to equal heights of elements there isn't a clear-cut way to do it and often a jQuery solution like the one below is required.

  1. Manual line-break - as requested in your question

Instead of doing an additional SQL query as mentioned, you can easily do it in the PHP in 2 different ways:

(a) loop through the rows before displaying them to calculate the title lengths, then loop again to display with/without the line break
or
(b) if you really down't want to loop twice, you could include the line break regardless of length as you loop once, but also calculate the line length in that loop. Then hide the line break using CSS if its not required

(a) 2 loops: Calculate length to determine whether to add the line break or not:

<?php
$maxchars = 41;
$cards = array();
$bLongTitle = false;

while ($row = mysql_fetch_assoc($rs_result)) {
    // save detaisl to $cards array
    $cards[$row["title"]] = $row["category"];
    // check title lengths until we find one over 41 - no need to check any more after that
    if (!$bLongTitle && strlen($row["title"])) > $maxchars)
        $bLongTitle = true;
}
?>
<div class="row">
<?php
foreach ($cards as $title => $category) {
    ?>
    <div class="col xl4 l4 m12 s12">
        <div class="card z-depth-5">
            <div class="card-content">
              <p><? 
                 // if there were any long title, wrap them all text
                 if ($bLongTitle) 
                     $title = wordwrap($title, $maxchars, "<br />\n");
                 echo $title;
              ?></p>
              <p>Category: <? echo $category; ?></p>
            </div>
        </div>
    </div>
    <?php
}
?>
</div>

(b) 1 loop: Always display line break, and hide it if not required

<div class="row">
<?php
$bLongTitle = false;
while ($row = mysql_fetch_assoc($rs_result)) {

    ?>
    <div class="col xl4 l4 m12 s12">
    <div class="card z-depth-5">
        <div class="card-content">
          <p class="cardTitle"><? echo wordwrap($title, $maxchars, "<br />\n"); ?></p>
          <p>Category: <? echo $row["category"]; ?></p>
          <?php 
             // check title lengths until we find one over 41 - no need to check any more after that
            if (!$bLongTitle && strlen($row["title"])) > $maxchars)
               $bLongTitle = true;
          ?>
       </div>

    </div>
    </div>
    <?php
};
?>
</div>
<?php if ($bLongTitle) {?>
    <script>.cardTitle br {display:none;}</script>
<?php } ?>
  1. CSS-only solution - not viable for the OP?

Because the titles are aren't direct siblings, the only way would be to fix the height of all title. This isn't a desirable solution, as I'm sure titles can vary a lot in length so its impossible to pick a "default" height to suit every possibility, and even that's complicated by the responsive width of the columns potentially changing the heights dynamically.

But for the sake of completeness:

  • add a class (e.g. .cardTitle) to the title in your loop
  • identify suitable heights for the title with and without a line break, and set these in your CSS
  • add the corresponding class (e.g. wrapTitle) to your <p> if any title is too long in a loop (similar to adding a line break above)

CSS

p.cardTitle { height:20px; } /* example of the default height for title */
p.cardTitle.wraptitle { height:40px; } /* example of height for wrapped title */

PHP (after looping through SQL rows to fill $cards array as option (a) above)

<?php
foreach ($cards as $title => $category) {
    ?>
    <div class="col xl4 l4 m12 s12">
        <div class="card z-depth-5">
            <div class="card-content">
                <p class="cardTitle <?php if ($bLongTitle) echo "wrapTitle"; ?>"><? echo $title; ?></p>
                <p>Category: <? echo $row["category"]; ?></p>
            </div>
        </div>
    </div>
    <?php
};
?>
  1. jQuery

You could use jQuery to loop through all elements to calculate the heights, and set them all to the tallest.

You could write the code yourself (see How to make all div columns of the same height automatically with jQuery or Setting equal heights for div's with jQuery but there is a library available to do this for you: matchHeight

Using the library, all you need to do is include it on your page and call it like this (assuming you've added the class cardTitle to the <p> that holds your title)

jQuery(document).ready(function() {
    $(".cardTitle").matchHeight();
});
FluffyKitten
  • 13,824
  • 10
  • 39
  • 52
  • I didn't see your post before this, but it seems one of your solutions is what I came up with, however I am going to read through your others to see if it can help me with the extra space. Thank you very much! – JayMax Aug 30 '17 at 22:08
  • I was noticing a couple issues with older computers and want the website to look perfect so I revisited your solution. Your jquery solution is perfect! I applied it to the card-content element instead as it would keep all the cards the same size, however I noticed that Category is right after the title when I need it at the bottom of the card. So its just extra space but I need it as a footer. Is there anyway to fix this? – JayMax Oct 15 '17 at 07:06
  • @JayMax Glad it helped! I'm not 100% sure what you are asking, but I think you'd need to use absolute positioning on your category in order to position it at the bottom of the card. But that introduces another set of issues by removing it from the flow which affects calculating the height of your card! If you know the height of the category element, you could add that on as padding. I suggest you ask separate question because (if I understand what you're looking for) its probably not on topic for this question and its unlikely to be a simple "quick fix" that can be answered a comment. :) – FluffyKitten Oct 15 '17 at 17:29
-2

I would perform a new SQL query first to see if any results have a title length of greater than 41 characters:

select count(*) from table where length(title)>41

And then set the result of this query to be a variable, e.g. $has41

You can then use an if statement within your loop ...

if($has41) {
    // do something with $row['title']
} else {
    // do something else with $row['title']
}
Chris
  • 4,672
  • 13
  • 52
  • 93
  • That would still only apply to the one title. I need it so that if one title in the 9 queries are longer than 41 characters it adds a line break to all of the titles: $limit = 9; if (isset($_GET["page"])) { $page = $_GET["page"]; } else { $page=1; }; $start_from = ($page-1) * $limit; $sql = "SELECT * FROM blog ORDER BY id DESC LIMIT $start_from, $limit"; $rs_result = mysql_query ($sql); – JayMax Aug 26 '17 at 23:51
  • No, i think my approach would work. Run the first query to see if any titles have a length of more than 41 characters. You then perform your existing query to loop through. Within the loop you know the result of the new query I gave you. This will then help you decide what you want to do to each title within the loop – Chris Aug 26 '17 at 23:52
  • @Shadow did you have a different idea? – JayMax Aug 27 '17 at 04:43
  • I think a CSS approach is probably best but my suggestion will work. In the absence of any better suggestions then why not give it a go? – Chris Aug 27 '17 at 17:54