Roger Dahl
Roger Dahl

Reputation: 15724

How do I let width of table determine width of entire page

I have an HTML page that contains a table. The table is dynamically generated from a database on the server side. I would like the width of the table to determine the width of the entire page. That is, other block elements above and below the table should take on the same width as the table.

I do not want to use fixed widths. I prefer a pure css solution but if fudging things with JavaScript is the only way, then so be it. I need fairly wide browser support.

I tried using a div with display: inline-block around the table and the other block elements. The idea was to have the div "shrink to fit" around the table and thereby set the width of the other elements. This did not work and I think it's because the div does not know which of the elements inside should be the "master", determining the width for the other elements.

Edit: Added a fiddle: http://jsfiddle.net/5Z3ru/. In this example, I would like the paragraph above the table to be the same width as the table (not the other way around). I do not want to use a fixed width for the table or paragraph.

Edit 2: Conceptually, what I am looking for can be imagined as if the table is rendered alone in a separate document. Then, the rendered table is inserted into a new document and the width of the rendered table is used for setting the width of the new document. So, nothing in the final document affected the rendering of the table, and the table width becomes the only factor in deciding the width of the final document.

Upvotes: 1

Views: 2284

Answers (5)

Inspiraller
Inspiraller

Reputation: 3806

I believe a previous answer here is correct already: treboothjd6.

Conclusion:

lt is not possible.

workarounds

Setting width

Regarding tables this is very unfortunate and in my opinion, this lack of css solution is a leading cause of css mess, because most css developers will set a width for either the entire table or its columns. This can cause inconsistencies with spacing and requires rigid strictness going forward with all further dimensions. Then use that same width for the other desired elements for better design constraints.

Getting computed table width with javascript

There is another solution which is less used, is a viable solution, but it does require javascript.

  1. Use javascript to place a className: eg: .jsEnabled or use equivalent - modernizr.
  2. In your css, hide the parent class, to prevent flashing, flickering, glitches of delayed browser rendering between previous width and desired width.
  3. In Javascript detect the computed width of the table. The table visibility is hidden, not none, so the browser still can detect its taken up width. Then use that width to dynamically set the desired other elements, ie the parent.
  4. Now use javascript to reshow the parent element.

Since most websites depend on js now anyway this solution provides the dynamic nature you are looking for with less css messiness going forward without having to adhere to a cascade of dimensions predetermined by a chosen width as in previous workaround.

Example codepen: https://codepen.io/inspiraller/pen/bGEeNeQ?editors=1111

js


const tablewidth = (strParentSelector, strTableSelector) => {
  const getWidth = $elem => {
    const computed = window.getComputedStyle($elem);
    return computed.getPropertyValue('width');
  };
  const setWidth = ($elem, width) => {
    $elem.style.width = width;
  };
  const show = $elem => {
    $elem.style.visibility = 'visible';
  }
 
  const $parent = document.querySelector(strParentSelector);
  const $table = document.querySelector(strTableSelector);
  const width = getWidth($table);

  setWidth($parent, width);
  show($parent);
};

const enableJS = () => {
  document.body.classList.add("jsEnabled");
}

const docReady = fn => {
    if (document.readyState === "complete" || document.readyState === "interactive") {
        setTimeout(fn, 1);
    } else {
        document.addEventListener("DOMContentLoaded", fn);
    }
}  

enableJS();
docReady(() => {
  tablewidth('.someParent', '.tableGeneric');
});

css

.jsEnabled .someParent {
  visibility: hidden;
}

html

<section class="someParent">
<table class="tableGeneric" summary="Test Diary">
  <thead>
    <tr>
      <th class="thtd thtd--date">
        DATE
      </th>
      <th class="thtd thtd--time">
        TIME
      </th>
      <th class="thtd thtd--cat_dudar_its_friend">
        CAT
      </th>
      <th class="thtd thtd--subcat">
        SUBCAT
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0100 ">0100</td>
      <td class="thtd thtd--sup ">sup</td>
      <td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
    </tr>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0200 ">0200</td>
      <td class="thtd thtd--feel ">feel</td>
      <td class="thtd thtd--tired ">tired</td>
    </tr>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0300 ">0300</td>
      <td class="thtd thtd--sup ">sup</td>
      <td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
    </tr>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0400 ">0400</td>
      <td class="thtd thtd--sup ">sup</td>
      <td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
    </tr>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0500 ">0500</td>
      <td class="thtd thtd--feel ">feel</td>
      <td class="thtd thtd--tired ">tired</td>
    </tr>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0630 ">0630</td>
      <td class="thtd thtd--sup ">sup</td>
      <td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
    </tr>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0700 ">0700</td>
      <td class="thtd thtd--sup ">sup</td>
      <td class="thtd thtd--zinc,_mag,_niacn_200mg ">zinc, mag, niacn 200mg</td>
    </tr>
    <tr>
      <td class="thtd thtd--2018 ">2018</td>
      <td class="thtd thtd--0800 ">0800</td>
      <td class="thtd thtd--feel ">feel</td>
      <td class="thtd thtd--tired ">tired</td>
    </tr>
  </tbody>
</table>
 <p>This text should nicely be the same width as the table. If it doesn't happen to be the same width as the table then this is not what I want. I reiterate, as its very important that this paragraph text does indeed wrap at the same width as the table.
</section>

React using Typescript and forwardRef example

Upvotes: 1

treboothjD6
treboothjD6

Reputation: 75

I've added

table {
 width:19.85em;
}

#wrap p {
    width:19.85em;
}

EMs are similar to PX but they are scalable. For that reason I use them for pretty much everything. I found the width of the table in EMs (and made it that just in case) and set that as the width of the wrap. You could remove the wrap and give the <p> a class with this width if you want. And you don't really need the width of the table to be 19.85em, but it's a good reminder of what the width of the <p> or wrap should be. Anyway, in any situation like this, try using EMs instead of PX because they're scalable.

Upvotes: 0

treboothjD6
treboothjD6

Reputation: 75

With a wrap div around both the table and the text, you would need to have reverse inheritance and have the wrap div inherit the width of the table. Unfortunately, though many of us want it, there is no reverse inheritance. Alternatively, you would just go straight to having the <p> element inherit the width of the table naturally, which is also impossible from what I know. The only way to inherit width is from the parent, so in this situation the parent of the <p> would have to be the table, which wouldn't work even if the table wasn't generated dynamically because putting the <p> element in table would affect its width and you'd end up telling the <p> element to inherit its own width. Reverse inheritance and a parent selector are in high demand but don't exist. I think the only way you can do this is with JavaScript.

I know of no way to do it only in HTML and CSS, so cheers to anyone who figures it out. I am intrigued by this question and I wonder if there is something I'm missing.

I believe JavaScript is the way to go.

Upvotes: 2

Eamonn
Eamonn

Reputation: 1320

  • Lets call the initially rendered width of the wrap as X.
  • wrap, when initially rendered and without any width specified, will automatically fill all available horizontal space on the screen available to it. In this case, the entire width of the document. Therefore, in this case, X = 100% of the document.
  • You cannot make X less than 100% without specifying a new width (aside from methods that are of no use here).
  • Using CSS, you can make the table the only deciding factor to the expansion of wrap, as it will naturally expand to include a table that grows beyond X.
  • To make the wrap shrink below X, to a dynamic value (the natural width of the table) you will have to use Javascript. This will mean that the document will load, then the table width is ascertained (var w = $( "table" ).width()), then that width is applied to wrap ($("#wrap").css("width":w)).

Upvotes: 2

Bernie
Bernie

Reputation: 5055

What about set tablels with relative?

table{
    width:100%;
}

Made a fiddle with a fixed body width and a table inside with 100% width.

Upvotes: 0

Related Questions