Table columns with relative size in HTML5 - css

I have a table with four columns. The first column needs to be the minimum size to fit the content, and the other three columns need to be equal sizes and consume the rest of the space in the table. Neither my table nor my content is of a known size. (It's a pretty standard variable-sized-label-and-fixed-size-data layout.)
In the good old days of HTML4 I could do this by using the specifying the size of each column as a proportion of the whole, using the 'relative size' functionality:
<colgroup>
<col width="0*"/>
<col width="1*"/>
<col width="1*"/>
<col width="1*"/>
</colgroup>
However, the width attribute is now deprecated and we're supposed to use CSS instead.
But I haven't found any way to replicate this with CSS; CSS size specifiers only let me specify the width as either a fixed size or a fraction of the whole, where what I actually need is a fraction of what's left after the first column is taken away.
Is there any way to do this using modern techniques? (Note that I can't use CSS3, though.)

I would use a little javascript in order to solve your problem: http://jsfiddle.net/qR9g2/
var tableSize = 400; // example of size
var firstCol = document.getElementById('firstCol_01');
var sizeOfFirstCol = firstCol.offsetWidth;
var myOtherCols = document.getElementsByTagName('td');
var nbcols = myOtherCols.length;
var sizeOtherCols = (tableSize-sizeOfFirstCol)/(nbcols-1);
for(var i=0;i<nbcols; i++)
{
if(myOtherCols[i].className === 'otherCols')
{
myOtherCols[i].style.width = sizeOtherCols+'px';
}
}
first give the size of the overall table. Then go get the size of the first column, and distribute the rest of the width to the other columns.
EDIT: here is a CSS solution. It is not perfect, but better than nothing: http://jsfiddle.net/qR9g2/2/
In the css, the main idea is the following:
.col1{
display:table;
float:right;
}
Add for the first column the tag display:table. This will work like a fit-content for all browsers.
Adding a float:right will push the first column onto the right and "stick" it to the rest of the table.
The visual result is exactly what you want. On the negative side, the problem is that your table takes more place then it seems (on the left). (basically if you have a 400px table with 4 columns, it will automatically give 4*100px for each column. adding the upper CSS solution will simply shift the col1 on the right side of the 100px that are given to that column).
You could always try to play with negative left-margins (i don't recommend) in order to shift your table on the left.

var table = document.getElementById('table');
var first_col = document.getElementById('first-col');
var total_col = document.getElementsByClassName('col').length
var rem_width = table.offsetWidth - first_col.offsetWidth;
var col = document.getElementsByClassName('col')
for(let i=0;i<col.length;i++){
col[i].style.width=rem_width/total_col+'px'
}
<table id="table" width="100%" border="1">
<tr>
<th id="first-col">NO</th>
<th class="col">ISBN</th>
<th class="col">Title</th>
<th class="col">Price</th>
</tr>
<tr>
<td>12</td>
<td>3476896</td>
<td>My first HTML</td>
<td>$53</td>
</tr>
</table>

Instead of trying to do a table, you can try a grid layout as follows.
Apologies for the inline css - obviously you would use classes instead but I just tested it quickly and it actually appears to work! I had not actually ever used this before, but making the first column "auto" actually does work and the layout is I think what you are looking for.
<div style="display:grid; grid-template-columns: auto repeat(3, 1fr);">
<div style="width: fit-content">This should fit the content that you decide to insert here</div>
<div>This should fit the content too</div>
<div>This should fit the content .. more text</div>
<div>This should fit the content and some more text</div>
</div>
I checked & grid has been around since 2011 so it's not too modern hopefully. I almost always do my tables with either grid or flexbox now..

Related

Adjusting custom view in Fullcalendar by Adam Shaw

I've followed the outlines in FullCalendar Change Week View to Vertical List instead of Horizontal Table Columns to create a custom vertical week view in fullcalendar.
The implementation is taken from the original post shown in this fiddle: http://jsfiddle.net/nomatteus/dVGN2/3/
This lays out the view like this:
<table>
<thead>
.tr.td.headercontent....
</thead>
<tbody>
.tr.td.eventcontent....
</tbody>
</table>
However the vertWeek view is used on small screens (smartphones etc), so I would like to have the day header and content to be layed out horizontal to take up less space in height like in this screenshot:
http://i.imgur.com/F4AkoSw.png
The MAN 8. is styled manually as I like it, but TIR 9 is how it is rendered by the view.
I would like to achieve this:
<table>
<thead>
</thead>
<tbody>
<tr>
<td> headercontent
<td> eventcontent
</tr>
</tbody>
</table>
I have tried to understand the fullcalendar code to move the header into the same as the eventcontent - but it seems like the view is rendered in different places for thead and tbody for that container.
Could anyone point me in the right direction on how to modify the code to achieve this?
Post of implemented answer for sharing:
Seems like my understandig was a litte bit inaccurate. The header was placed in an overlapping table above the table containing the events. Tried to traverse the DOM and place the header during the dayRender function, but the corresponding tbody for the event was not yet created.
Simplified illustration:
table
thead
**header**
tbody
table
thead
tbody (not created at dayRender, but available at eventRender)
**event*
The solution was quite simple - hide the .fc-day-number:
dayRender: function( date, cell ) {
// Get the current view
var view = $('#meal_calendar').fullCalendar('getView');
// Check if the view is the new vertWeek -
// in case you want to use different views you don't want to mess with all of them
if (view.name == 'vertWeek') {
// Hide the widget header - looks wierd otherwise
$('.fc-widget-header').hide();
// Remove the default day number with an empty space. Keeps the right height according to your font.
//$('.fc-day-number').html('<div class="fc-vertweek-day"> </div>');
$('.fc-day-number').hide();
// Create a new date string to put in place
var this_date = date.format('ddd, MMM Do');
// Place the new date into the cell header.
cell.append('<div class="fc-vertweek-header"><div class="fc-vertweek-day">'+this_date+'</div></div>');
}
},
In addition I styled the td.fc-event-container in my CSS like this:
td.fc-event-container {
padding-left: 68px;
}
Quite possibly a hack - hours to research, two lines to correct. But works for me......

Wrap text from bottom to top

Anybody know how I could wrap the text in reverse order, from bottom to top?
I attached an example image.
[][http://i.stack.imgur.com/RVsIG.jpg]
Instead of breaking the line after it is full and having an incomplete line at the end, I need to brake somehow from bottom to top, so bottom lines are full and top line is incomplete.
I would not recommend using exotic CSS attributes which aren't even in Chrome & Firefox yet. The best cross-browser solution is to handle this in Javascript when the document loads. Here's a sketch of how to do that:
$(function() {
$(".title").each(function(i,title) {
var width = 0;
var originalHeight = $(title).height();
var spacer = $('<div style="float:right;height:1px;"/>').prependTo(title);
while (originalHeight == $(title).height()) {
spacer.width( ++width );
}
spacer.width( --width );
});
});
Working JSFiddle is here: http://jsfiddle.net/zephod/hfuu3m49/1/
6 years later, but fret not! I have found a pure CSS solution!
Turns out you can achieve this result with flexbox, but it's not obvious or very straight forward. This is what I started out with:
I want the header to be "bottom-heavy", the same effect as you describe in the question.
I began by splitting up my string by whitespace and giving them each a <span> parent. By using flex-wrap: wrap-reverse, and align-content: flex-start. You will achieve this:
Oh no! Now the order is messed up! Here comes the trick. By reversing both the order in which you add spans to the HTML and the direction order of flex with 'flex-direction: row-reverse', you actually achieve the "pyramid-shaped" upwards overflow effect you desire.
Here is my (simplified) code, using react and react-bootstrap:
<Row className='d-flex flex-wrap-reverse flex-row-reverse align-content-start'>
{props.deck.name
.split(' ')
.reverse()
.map(word => (
<span className='mr-1'>{word}</span>
))}
</Row>
There is no general css solution for it. You must have to utilize help of any language.
This is one of the solution using PHP:
<?php
$str= "This is what I want to achieve with your help";
$str = strrev($str);
$exp = str_split($str,18);
$str = implode(">rb<", $exp);
echo strrev($str);
?>
Well, if that is depending on the text, then you can try something like a word replacer. For example
var words = "This is what I want to achieve";
var newWords.replace("what", "what <br />"); // note the line break
document.write(newWords);
Here is a fiddle for you: http://jsfiddle.net/afzaal_ahmad_zeeshan/Ume85/
Otherwise, I don't think you can break a line depending on number of characters in a line.
Wrap and Nowrap will be rendered by the client-browser, so you can not force the browser to wrap from bottom to top. but you can do that with javascript or asp.
This is not a formal solution for this problem. But see if this helps.
The HTML CODE
<div id="mydiv">
I can imagine the logic behind the code having to detect what is the last line, detect the div size, and the font size... then measure how many characters it can fit and finally go to the above line and insert the break where necessary. Some font families might make this harder, but trial and error should solve the issue once the basic code is set..
</div>
CSS:
#mydiv
{
width:1000px;
line-height:18px;
font-size:20px;
text-align:justify;
word-break:break-all;
}
Here setting the div width around 50 times that of the font-size will give you the precise result. Other width values or font values might slightly disorient the last line, giving some blank space after the last character.(Could not solve that part, yet).
JQuery:
$(document).ready(function(){
//GET the total height of the element
var height = $('#mydiv').outerHeight();
//Get the height of each line, which is set in CSS
var lineheight = $('#mydiv').css('line-height');
//Divide The total height by line height to get the no of lines.
var globalHeight = parseInt(height)/parseInt(lineheight);
var myContent = $('#mydiv').html();
var quotient = 0;
//As long as no of lines does not increase, keep looping.
while(quotient<=globalHeight)
{
//Add tiny single blank space to the div's beginning
$('#mydiv').html(' '+myContent);
//Get the new height of line and height of div and get the new no of lines and loop again.
height = $('#mydiv').outerHeight();
lineheight = $('#mydiv').css('line-height');
quotient = parseInt(height)/parseInt(lineheight);
myContent = $('#mydiv').html();
}
//get the final div content after exiting the loop.
var myString = $('#mydiv').html();
//This is to remove the extra space, which will put the last chars to a new line.
var newString = myString.substr(1);
$('#mydiv').html(newString);
});
If you already know where you want your breaks to take place just use simple HTML breaks to break your content and have it display the way you want.
<p>This is what<br/>
want to acheive with your help</p>
If you set the breaks manually (and you know where you want them to break) then create them yourself.
You could also try setting separate css width adjustments based on the dimensions of the screen you are seeing the breaking you are not liking and set an #media reference to make the div width smaller to break the text so it doesn't run unevenly across the top of certain size devices.
Use display: inline-block; on the text div.

Adjust size based on height (vertical length)

I am doing a div that needs to display the whole content of a text field and adjust the text size dynamically so that it will not overflow.
To get an idea of the problem, look here http://sandbox.littlegraffyx.com/bible/
You can try entering verses at lower left text box using the format GEN 1:1 for "Genesis 1:1"
My problem is when I try to display long verses, they get truncated. I need to change the size based on how long the current text is. Is there some css that can be applied based on text field size?
As mentioned in the comments, it isn't possible to scale text based on the height of its containing element using pure CSS. But here's a small jQuery script I have used in the past when I needed to achieve what you want. It also adjusts the text size when the user resizes the browser window.
HTML:
<p class="quote">
Really long text goes here...
</p>​
CSS:
.quote {
// The largest size to display text at.
font-size: 36px;
}​
JS:
$(window).bind('resize',function(e){
scaleQuote();
});
function scaleQuote(){
var quote = $('.quote');
var winH = $(window).height();
// Reset font size.
quote.css('font-size', '');
// If quote is larger than viewport, reduce font-size until it fits.
while (winH < (quote.height())){
var fontSize = parseInt(quote.css('font-size'), 10);
quote.css('font-size', fontSize-1+'px');
}
}
scaleQuote();​
Demo: http://jsfiddle.net/eCBmc/2/
You can try something like this. It will set input field to 10 character, and if it's bigger it increase it's size.
http://jsfiddle.net/4qjjf/1/
<html>
<body>
<textarea cols="10" rows="1" id="shit"
onkeyup="this.cols=this.value.length>10?this.value.length:10;"></textarea>
</body>
</html>​

How can I create a max-width and max-height effect on an image sent in an HTML email?

My app sends out HTML emails containing one or more images of unknown size and width/height ratios. The effect I want is
<img style="max-width: 200px; max-height: 200px;" src="..." />
however, it seems like most email clients, including Gmail and Outlook 2010, ignore this css. Simply setting width and height doesn't work because the image is not square, and I don't know the size and ratio ahead of time.
With unknown sizes of images, the programmatic route will work: while processing/building your email, you'll have to peek at the dimensions of the images and set the height and width accordingly in the html.
This way you'll be sure to have correctly scaled images across all (or most:) ) clients.
Unfortunately there are not much CSS properties that are widely supported in email clients.
Here is a chart about the current situation.
I can only think of an option like what #Groovetrain suggested, or instead generating thumbnails programmatically from the images, storing them, and using those in the email.
If you can't do a programmatic solution like Groovetrain suggested, the best route is to
Know the max & min dimensions that are possible for the image that'll appear.
Make sure the containing element allows for the max dimensions.
In the containing element, set the horizontal & vertical alignment (and if necessary the padding) so that the email looks acceptable with both the largest and smallest possible images.
I work with an email system with limited API support, so sometimes I have had to put my foot down and insist that the images we're working with be resized before being uploaded.
I know this is old, but I've just had to implement this. Based on what Groovetrain suggests - programmatically looking at the image when you build your email html code - here's some C# ASP.NET code that restricts the width of an image to 600 if it is too large:
string imgPth = HttpContext.Current.Server.MapPath("/images/yourimage.jpg");
System.Drawing.Image img = System.Drawing.Image.FromFile(imgPth);
string emailImage = "<img src='http://www.yourdomain.com/images/yourimage.jpg'";
if (img.Width > 600)
emailImage += " width='600' style='width:600px;'";
emailImage += "/>";
Then obviously add emailImage to your email body.
You can use this method to control width :
<table width="100%"> <!-- a width 100% container -->
<tr>
<td></td> <!-- an empty cell, which will adapt its width -->
<td width="200"> <!-- it's like max-width:200px -->
<img src="your_image" width="100%" />
</td>
<td></td> <!-- another empty cell, which will adapt its width -->
</tr>
</table>
This tip should work. If your screen is less than 200px wide, image should appear smaller too !
By default, image will be center ! If you want it to be aligned left or right, try delete the 1st empty cell, or the last (depending on what you wanna do !)
For max-height, i have no idea... In this case, height will be auto-calculated !
Hope that will help you mates !
Edit : i agree with the best answer ! If a script constructs your email, ask your script to pick up the width and height, and adapt your code. it should work...
I toke the programmatic solution from Groovetrain into pseudocode
(and later into Twig for Shopware 6 mails):
maxWidth = 75
maxHeight = 75
realWidth = 444
realHeight = 1096
widthRatio = realWidth / realHeight = 0.4051094890510949
heightRatio = realHeight / realWidth = 2.468468468468468
if realWidth > realHeight
// use max height
newHeight = maxHeight
newWidth = newHeight * widthRatio
else
// use max width
newWidth = maxWidth
newHeight = newWidth * heightRatio
results width = 30.3832116788 and height = 75

Is it possible to change the position of generated <tr> by css?

Some asp.net controls generate , so to customize its appearance (e.g. childview in grid) i need to change the position of < tr> content. I don't know any ways to change position. The only idea is to generate div wrappers by javascript. Does anybody know a better way?
if you want to "move" the tr to another place, you can try:
<table>
<tr id="tr1"><td>test</td><td>test2</td></tr>
<tr id="tr2"><td>test3</td><td>test4</td></tr>
<tr id="tr3"><td>test4</td><td>test5</td></tr>
</body>
<script>
var tr = document.getElementById("tr2");
tr.style.display = 'block';
tr.style.position = 'absolute';
tr.style.top = "100px";
tr.style.left = "100px";
</script>
it definitely works in firefox (dont know about ie6-8). If you want to exchange the content with another tr, thats even easier (you just remove/add the tr nodes).

Resources