How to expand input field to the right in a header bar - javascript

I have a header bar with left-aligned items, center items and right-aligned items. In the center, I have multiple items and a search input field. When the search field gets focus, I'm making it wider by animating the width. Right now, because the items are centered, it's animating both left and right to center the content. How can I change this so it keeps the alignment and expands the width to the right?
I'm not using Bootstrap.
I'm currently using a table for the header bar content. I'm open to changing that, but if there's a way to do it with the current design, that would be preferred.
Here's a JSFiddle...click in the search field to see what's happening: https://jsfiddle.net/L60g0j64/1/
EDIT: I've updated it with the suggested solution below. My only issue is that the red container surrounding the input should expand also.
HTML/CSS/JS Snippet
$('#search').focus(function() {
$(this).val("");
$('#hidden_content').css('display','inline');
$(this).animate({width: '180px'}, 200);
});
$('#search').blur(function() {
$(this).val('Search');
$('#hidden_content').css('display','none');
$(this).animate({width: '120px'}, 200);
});
.header-navbar {
cursor: pointer;
white-space: nowrap;
background-color: #1f2127;
color: #cbcbcb;
min-width: 0;
text-overflow: ellipsis;
z-index: 299;
top: 0px;
left: 0px;
width: 100%;
height: 32px;
float: none;
position: fixed;
border-spacing: 0px;
}
td.cell-center {
text-align: center;
}
.cell-center table {
margin: 0 auto;
}
.header-table {
height: 32px;
border: none;
border-spacing: 0px;
}
td.header_rtd {
padding-right:12px;
}
td.header_ltd {
padding-left:12px;
}
.search-wrapper {
max-width: 124px;
background-color: red;
padding:4px;
}
.hidden_content{
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="header-navbar" id="header" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td>
<table class="header-table" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class='header_rtd'>left1</td>
<td class='header_rtd'>left2</td>
</tr>
</table>
</td>
<td width=100% class='cell-center'>
<table class="header-table" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class='header_rtd'>center</td>
<td class='header_rtd'>center</td>
<td><div class="search-wrapper">
<input class="search" id="search" style="width: 120px;" type="text" size="60" value="Search"/>
<div class='hidden_content' id='hidden_content'>
hidden content
</div>
</div></td>
</tr>
</tbody>
</table>
</td>
<td>
<table class="header-table" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class='header_ltd'>right1</td>
<td class='header_ltd'>right2</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>

One quick solution would be to give the parent element a max-width equal to the initial width of the element. In doing so, the element will still be centered relative to the initial width because the input element's animated width will not effect the width of the parent element.
Updated Example
.search-wrapper {
max-width: 124px;
}
As a side note, you don't need jQuery/JS to animate the width, you can simply use a CSS transition along with the :focus pseudo-class.
Updated Example
.search-wrapper input.search {
transition: 1s width ease;
width: 120px;
}
.search-wrapper input.search:focus {
width: 180px;
}

Related

How to style element to overlap scroll

I am working on an already existing project, with a pretty complex front end. I want to introduce a new element which should be a substitute for a dropdown. Basically it's a div bind with knockout to a collection.
The problem I have is that on a single page there are several divs inside which a more complex structure is rendered for each one, and inside one of this divs is my custom dropdown. The problem is that when I try to expand the dropdown (a class bind to a click event using jQuery) my "dropdown" is rendered up to the top of the div because of the fact that there is too much content and in order to preserve the entire page look and appearance there is no good way to use overflow: visible.
A snippet that pretty well introduce my problem is HERE :
$('.show-dropdown').click(function() {
if ($(this).next('.render-this').hasClass('hide-me')) {
$(this).next('.render-this').removeClass('hide-me');
} else {
$(this).next('.render-this').addClass('hide-me');
}
})
td {
position: relative;
}
#top-div {
width: 500px;
max-width: 500px;
border: 1px solid black;
max-height: 100px;
overflow-y: auto;
white-space: nowrap;
}
#bottom-div {
width: 500px;
max-width: 500px;
border: 1px solid black;
max-height: 100px;
overflow-y: auto;
}
.show-dropdown {
width: 120px;
height: 40px;
background-color: green;
}
.render-this {
position: absolute;
bottom: 10px;
z-index: 5;
width: 20px;
height: 150px;
background-color: red;
}
.hide-me {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
<p>
lorem ipsum lorem ipsum lorem ipsum lorem ipsumlorem ipsumlorem ipsum lorem ipsum lorem ipsum
</p>
</div>
<div id="bottom-div">
<table class="w3-table">
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
<th>Column 5</th>
<th>Column 6</th>
</tr>
<tr>
<td><div class="show-dropdown"></div><div class="render-this hide-me"></div></td>
<td><div class="show-dropdown"></div><div class="render-this hide-me"></div></td>
<td><div class="show-dropdown"></div><div class="render-this hide-me"></div></td>
<td><div class="show-dropdown"></div><div class="render-this hide-me"></div></td>
<td><div class="show-dropdown">></div><div class="render-this hide-me"></div></td>
<td><div class="show-dropdown"></div><div class="render-this hide-me"></div></td>
</tr>
</table>
I've read a lot about this topic. My conclusion so far is that if you have overflow it is pretty much game over. However from the question HERE I see that with transform and maybe some other CSS it might be still possible to achieve something. Also, what I need is to render my dropdown completely, I was also thinking about using overflow: visible and some sort of JS created scroll, but haven't dig deep for this still.
Demo
https://jsfiddle.net/mg8zbr41/172/
(I hope this was the desired behaviour)
Explanation
The whole problem would have been solved if we were allowed to have overflow-x: auto and overflow-y: visible together. But we cannot do that (see this answer). So we use the following workaround.
If you want to have want the red div to pop out you cannot put
position: relative parent. So we remove that first
Now bottom becomes relative to parent relative element i.e. body but we don't want that so we also remove bottom
Now we have top, right, bottom, left all as auto. So the elements placed below the green box as it would have been if it was static. The only difference is it pops out of the bottom box
Now we want it to be 10px above the green box for that we use translateY(calc(100% + 10px) * -1)
Now this works till there's no scrolling. When the div is scrolled the red box stays there and doesn't move with its green box, we need to fix that
This can be easily fixed if we know how much is the div scrolled. Suppose the div is scrolled by 100px towards left we'll shift the red box towards left by 100px
We cannot find scrollLeft without JS. I personally don't like JS intervention for styling. We cannot avoid it but at least we can make it more semantic by using css variables for communication between JS and CSS.
We use JS to update a --scroll-left css variable on #bottom-div with the scrollLeft value
Once we have --scroll-left we can now add translateX(calc(var(--scroll-left,0px) * -1))
Also we don't want the red box to pop out of the box horizontally. We cannot fix this by overflow: hidden because that would require position: relative. So we use clip-path: inset(-999px 0px -999px 0px).
Finally we achieved want we wanted. Phew.
Demerits:
Horizontal repositioning will be laggy in Firefox because of Scroll Lined Effects. Same might be the problem in mobile browsers
See also:
https://css-tricks.com/popping-hidden-overflow/ Source of inspiration for my answer but both (solution in the article and my solution) are quite different but same core approach
You can add a wrapper div with relative position around the scrollable container and then your absolute positioned dropdown would bind to that element. As you can see in this example.
css:
.position-relative {
position: relative;
}
#top-div {
width: 500px;
max-width: 500px;
border: 1px solid black;
max-height: 100px;
overflow-y: auto;
white-space: nowrap;
}
#bottom-div {
width: 500px;
max-width: 500px;
border: 1px solid black;
max-height: 100px;
overflow-y: auto;
}
.show-dropdown {
width: 120px;
height: 40px;
background-color: green;
}
.render-this {
position: absolute;
bottom: 10px;
z-index: 5;
width: 20px;
height: 150px;
background-color: red;
}
.hide-me {
display: none;
}
html:
<div class="position-relative">
<div id="bottom-div">
<table class="w3-table">
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
<th>Column 5</th>
<th>Column 6</th>
</tr>
<tr>
<td>
<div class="show-dropdown"></div>
<div class="render-this hide-me"></div>
</td>
<td>
<div class="show-dropdown"></div>
<div class="render-this hide-me"></div>
</td>
<td>
<div class="show-dropdown"></div>
<div class="render-this hide-me"></div>
</td>
<td>
<div class="show-dropdown"></div>
<div class="render-this hide-me"></div>
</td>
<td>
<div class="show-dropdown">></div>
<div class="render-this hide-me"></div>
</td>
<td>
<div class="show-dropdown"></div>
<div class="render-this hide-me"></div>
</td>
</tr>
</table>
</div>
</div>
js
$('.show-dropdown').click(function() {
if ($(this).next('.render-this').hasClass('hide-me')) {
$(this).next('.render-this').removeClass('hide-me');
} else {
$(this).next('.render-this').addClass('hide-me');
}
})
Then you can adjust the top, left, right, bottom properties as you wish.
If you change your CSS as follows, you can get this to work as you would like:
Remove the position:relative; from your td.
Use a different approach to make the #bottom-div expend to it's content, using display: table;, and also apply the position:relative; to it.
all other css rules stay the same.
So, this is your new css:
#top-div {
width: 500px;
max-width: 500px;
border: 1px solid black;
max-height: 100px;
overflow-y: auto;
white-space: nowrap;
}
#bottom-div {
width: 500px;
max-width: 500px;
border: 1px solid black;
max-height: 100px;
position: relative;
display: table;
}
.show-dropdown {
width: 120px;
height: 40px;
background-color: green;
}
.render-this {
position: absolute;
bottom: 10px;
z-index: 5;
width: 20px;
height: 150px;
background-color: red;
}
.hide-me {
display: none;
}
Here is a link to a Fiddle with the new css.

How to get thead to the top on scrolling

I have problem creating sticky thead, my first 3 columns are fixed, rest of data is scrollable horizontal. I'm using jquery library for the sticky header, but position fixed is destroying my horizontal scroll, displaying all elements on the page.
I need sticky header to stay at the top, and at the same time horizontal scroll to work.
This is how it should look but with sticky header.
enter image description here
.horizontal-scroll-access-point {
display: block;
overflow-x: auto;
white-space: nowrap;
thead,tbody {
tr {
//First three elements are fixed
th,td {
&:nth-child(1), &:nth-child(2), &:nth-child(3){
background-color: white;
position:absolute;
text-align: center;
width: 100px;
padding-bottom: 10px;
z-index: 1;
}
&:nth-child(1) {
left: 0;
}
&:nth-child(2) {
left: 100px;
}
&:nth-child(3) {
left: 180px;
}
&:nth-child(4) {
padding-left: 300px;
}
}
}
}
}
<table class="table monthTable horizontal-scroll-access-point" ng-if="showActions()">
<thead class="sticky-header" sticky-divs sticky-divs-margin-top="50">
<tr>
<th class="heading" translate>SH_Area</th>
<th><span translate>AP_openClose</span></th>
<th translate>AP_maxUnits</th>
<th class="hour hover-cell" ng-repeat="hour in apu.hours" ng-click="changeUnitsAllByHourModal(hour)" on-finish-render>
<span ng-bind="hour | hourminute"></span>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="area in apu.areaHours">
<td ng-class="area.closed ? 'closed-cell' : 'hover-cell'" ng-click="changeUnitsAllByAccessPointModal(area)"><strong ng-bind="area.accessPointName"></strong></td>
<td class="open-close-cell">
<button type="button" class="btn btn-xs" ng-class="area.closed ? 'btn-danger' : 'btn-success'" ng-click="switchAreaStatus(area)" translate>{{ area.closed ? 'AP_closed' : 'AP_opened' }}</button>
</td>
<td class="gradient-cell-green" ng-bind="area.maxUnits">
</td>
<td ng-class="area.closed ? 'closed-cell' : 'hover-cell'" style="background-color: rgba(110, 170, 120, {{ hour.units / area.maUnits }})" ng-repeat="hour in area.hours" ng-click="changeUnitsModal(area, hour)">
<span ng-bind="area.closed ? '0' : hour.units"></span>
</td>
</tr>
</tbody>
</table>
You should only change the position of thead and then give each one of the th elements the same width as the width of the widest tr element in that column.
I assume your table is responsive. If so, write some js code to do so.

CSS/HTML fixed position element resizing when browser resizing

This is my situation: I have a table with table header position: fixed and a couple of table body rows with their width set to 100%.
I am trying to make the header row resize properly when browser resizes, so its cells lines up body row cells.
How am I going to achieve that? (trying to make a position: fixed element react to browser size-change dynamically)
Here is my code. A very simple webpage
<html>
<head>
<style>
body{
width:100%;
}
thead{
position:fixed;
width:100%
overflow:visible;
align:center;
}
th{
border:2px solid black;
width:20%;
text-align:center;
}
td{
border:2px solid black;
width:20%;
text-align:center;
}
table{
width:80%;
margin:auto;
margin-top:50px;
}
.empty{
height:30px;
}
.empty td{
border:none;
}
</style>
</head>
<body>
<table>
<thead>
<th>
heading1;
</th>
<th>
heading2;
</th>
<th>
heading3;
</th>
<th>
heading4;
</th>
<th>
heading5;
</th>
<thead>
<tbody>
<tr class="empty">
<td></td><td></td><td></td><td></td><td></td>
</tr>
<tr>
<td>
cell1;
</td>
<td>
cell2;
</td>
<td>
cell3;
</td>
<td>
cell4;
</td>
<td>
cell5;
</td>
</tr>
<tr>
<td>
cell1;
</td>
<td>
cell2;
</td>
<td>
cell3;
</td>
<td>
cell4;
</td>
<td>
cell5;
</td>
</tr>
<tbody>
</table>
</body>
</html>
I'm developing a website tool using ASP.net currently. Any solution in ASP.net will be much appreciated.
The table element is not quite flexible as other in the html. Aparently the 'position:fixed' property will make the table ignore the width specification.
Therefore I tweaked your html and css a bit, in order to better divide the document's parts into header and content (section).
Basically, the header will contain only the table head.
The section will contain all the table rows and data in it. When scrolling, the header element will remain fixed and the table head cells in it (which has been given the exact same css attributes as the td cells) will remain perfectly aligned with their respective columns.
Hope this helps, good luck.
body {
width: 100%;
margin: 0px;
}
header {
width: 100%;
position: fixed;
margin-top: -30px;
}
section {
width: 100%;
margin-top: 50px;
}
table {
width: 80%;
margin: 0px auto;
}
header table th,
section table td {
width: 20%;
text-align: center;
border: 2px solid black;
}
<header>
<table>
<thead>
<th>heading1;</th>
<th>heading2;</th>
<th>heading3;</th>
<th>heading4;</th>
<th>heading5;</th>
</thead>
</table>
</header>
<section>
<table>
<tbody>
<tr>
<td>cell1;</td>
<td>cell2;</td>
<td>cell3;</td>
<td>cell4;</td>
<td>cell5;</td>
</tr>
<tr>
<td>cell1;</td>
<td>cell2;</td>
<td>cell3;</td>
<td>cell4;</td>
<td>cell5;</td>
</tr>
</tbody>
</table>
</section>

Get image to overlay on top of table

I have a table of basketball stats and I have an image of a basketball court that will later contain a shot chart. It is initially hidden. I want the image to only appear when the user clicks a button. And the image should appear on top of the of table. (Most of the table will be behind the image)
I can't seem to manipulate the CSS or Jquery position to allow that to happen. Part of the problem is that I want the table itself to be centered (margin: 0px auto;)
I started a JSFiddle here: https://jsfiddle.net/Thread7/f7g9dtxt/ to work it out. If you click "Show Court" you will see what happens now. The image is at the bottom and to the left. Instead of the top and middle.
Code Below:
<button id='showimg'>
Show Court
</button>
<table class='mytable'>
<tr><th>Name</th><th>FGA</th><th>FGM</th><th>Rebounds</th><th>Fouls</th> </tr>
<tr><td>Michael Jordan</td><td>5</td><td>10</td><td>12</td><td>3</td></tr>
<tr><td>LeBron James</td><td>3</td><td>7</td><td>5</td><td>4</td></tr>
<tr><td>Kobe Bryant</td><td>1</td><td>8</td><td>7</td><td>3</td></tr>
<tr><td>Magic Johnson</td><td>6</td><td>11</td><td>3</td><td>3</td></tr>
<tr><td>Draymond Green</td><td>6</td><td>11</td><td>3</td><td>3</td></tr>
<tr><td>Zach Randolph</td><td>6</td><td>11</td><td>3</td><td>3</td></tr>
</table>
<img src='http://exchangedownloads.smarttech.com/public/content/2c/2c4cb6ee-579f-4404-b573-c554ba6bf7f4/previews/medium/0001.png' class='myimg' id='court'>
CSS:
.mytable {
margin: 0px auto;
}
.mytable td {
text-align: left;
border: solid;
padding: 5px;
margin: 0px;
}
.myimg {
display: none;
margin: 0px auto;
}
JQuery:
$("#showimg").click(function(e) {
$("#court").show();
});
You should wrap your table in element with relative position, than place the image (also in container with absolute position). That way you have better control over those elements. Check it out:
$("#showimg").click(function(e) {
$(".myimg").toggle();
});
.mytable {
margin: 0px auto;
}
.mytable td {
text-align: left;
border: solid;
padding: 5px;
margin: 0px;
}
.myimg {
display: none;
position: absolute;
top: 0;
width: 100%;
text-align: center;
}
.table_container {
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='showimg'>
Show/Hide Court
</button>
<div class="table_container">
<table class='mytable'>
<tr>
<td>Michael</td>
<td>Jordan</td>
<td>5</td>
<td>10</td>
</tr>
<tr>
<td>LeBron</td>
<td>James</td>
<td>3</td>
<td>7</td>
</tr>
<tr>
<td>Kobe</td>
<td>Bryant</td>
<td>1</td>
<td>8</td>
</tr>
<tr>
<td>Magic</td>
<td>Johnson</td>
<td>6</td>
<td>11</td>
</tr>
</table>
<div class="myimg">
<img src='http://exchangedownloads.smarttech.com/public/content/2c/2c4cb6ee-579f-4404-b573-c554ba6bf7f4/previews/medium/0001.png' id='court' />
</div>
</div>
Also at updated fiddle
Try this: https://jsfiddle.net/f7g9dtxt/3/
$('.yourImage').toggle();
$("#showimg").click(function(e) {
$('.yourImage').toggle();
});
.mytable td {
text-align: left;
border: solid;
padding: 2px;
margin: 0px;
}
.mytable {
position: absolute;
z-index: 0;
}
.yourImage {
position: absolute;
z-index: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='showimg'>
Show Court
</button>
<table class='mytable'>
<tr><td>Michael</td><td>Jordan</td><td>5</td><td>10</td></tr>
<tr><td>LeBron</td><td>James</td><td>3</td><td>7</td></tr>
<tr><td>Kobe</td><td>Bryant</td><td>1</td><td>8</td></tr>
<tr><td>Magic</td><td>Johnson</td><td>6</td><td>11</td></tr>
</table>
<span class="yourImage">
Put an img tag here!
</span>

Div and a Table side by side?

So I have 2 Div's one with a form and one with a table. the problem is that the table div is coming below the form div. I tried using float right, and overflow css attributes. but still no success.
CSS styling of my table: jsFiddle
Full webpage here
HTML:
<div id="existing_ledgers">
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Job Title</th>
</tr>
</thead>
<tbody>
<tr>
<td>James</td>
<td>Matman</td>
<td>Chief Sandwich Eater</td>
</tr>
<tr>
<td>The</td>
<td>Tick</td>
<td>Crimefighter Sorta</td>
</tr>
</tbody>
</table>
</div>
Put everything in a parent div, give the parent div display:inline-block
Then give float right/left to your child divs
Example
#registration-form {
display: inline-block;
float: left;
}
#existing_ledgers {
display: inline-block;
float: left;
}
use this css in your web page
.DA_custom_form {
float: left;
margin: 0 auto 5em;
max-width: 600px;
padding: 0 10px;
position: relative;
z-index: 1;
}
#el {
float: right;
margin: 0 auto;
max-width: 600px;
}
using float left and defined widths of the containers: they have to fit into the container, both being 50% wide will solve the problem.
here you have a working example:
http://jsfiddle.net/qLGJt/
#one, #existing_ledgers{float:left; width:50%; }

Categories