Ensure that column headers remain fixed when scrolling side to side

I'm trying to adjust the column headers so that I can scroll horizontally while keeping the headers visible. I've attempted the following changes but haven't been successful. In the screenshots provided, you can see that when I scroll up or down, the headers don't stay in place and there is some improper overlapping. The first td always ends up hidden behind the th.

Screenshot 1https://i.sstatic.net/3VblS.png

Screenshot 2 https://i.sstatic.net/D2upr.png

   th:first-child {
        position: fixed;

    } 

        th {
            position: fixed;
        }
.fixed-side {
    border:1px solid #000;
    background:#eee;
    visibility:visible;
}

CSS

<style>
    th,
    td {
        padding: 7px;
        min-width: 300px;
        max-width: 300px;
    }

    /* th:first-child {
    position: fixed;

} */


    th {
        position: fixed;
    }

    .fundClassesTable {

        table-layout: fixed;
    }


    .cellbgcolor {
        color: transparent;
    }

    .btn {}

    .tableItem {
        text-align: left;
        border-left: solid 1px lightgrey;
        border-top: solid 1px lightgrey;
        border-right: solid 1px lightgrey;
        border-bottom: solid 1px lightgrey;

    }

    .rowItem:hover {
        background-color: #f5f7f7;
    }


    label {
        margin-left: 0.5rem;
        vertical-align: middle
    }


    .panel-heading {
        color: black;
        border-color: #ddd;
        overflow: hidden;
        padding-top: 5px !important;
        padding-bottom: 5px !important;
    }

    .panel-heading .left-label {
        display: inline-block;
        padding-top: 5px !important;

    }

    .scrollClass {
        overflow-x: scroll;
        display: grid;

    }

    .panel-heading label {
        margin-bottom: 0px !important;
    }

    #FundClass tr:hover {
        background-color: #ECF0F1;
    }

    .headcol {
        position: absolute;
        min-width: 300px;
        max-width: 300px;
        width: 5em;
        left: 0;
        top: auto;
        border-top-width: 1px;
        /*only relevant for first row*/
        margin-top: -1px;
        /*compensate for top border*/
    }

    .headcol:before {
        content: 'Row ';
    }

    .collapsed {
    color: #d6630a;
    font-size: 22px;
    text-decoration: none;
    font-weight: bold;
}

.expanded {
    color: #d6630a;
    font-size: 22px;
    text-decoration: none;
    font-weight: bold;

}

.fixed-side {
    border:1px solid #000;
    background:#eee;
    visibility:visible;
}

</style>

HTML

<div class="card">
    <div class="card-header panel-heading">
        <span class="left-label" style="font-size: 18px; font-weight: bold; ">Fund Classes</span>

        <a class="pull-right" [ngClass]="{'collapsed': !isExpanded, 'expanded': isExpanded }" data-toggle="collapse"
            href="javascript:void(0);" (click)="expand()" role="button" [attr.aria-expanded]="isExpanded"
            aria-controls="fundClass"> {{ isExpanded ? '-' : '+' }}
        </a>

        <div *ngIf="CanEdit" class="pull-right"
            style="padding-right:10px; display: inline-block; vertical-align:middle">
            <button style="text-align: center; vertical-align:middle" class="btn btn-default pull-right"
                (click)="openFundClassModal()"> <i data-bind="visible: true" class="fa fa-plus-square"></i> Add
                Class</button>
        </div>
        <div class="pull-right" style="padding-right:10px; display: inline-block; vertical-align:middle">
            <label style="text-align: center; vertical-align:middle" class="btn btn-primary"
                [ngClass]="{'btn-primary': InvestedOnly, 'btn-default': !InvestedOnly }"><input type="checkbox"
                    (click)="isInvestedSelected($event)" checked="checked" [(ngModel)]="InvestedOnly" class="hidden"
                    for="chkInvested" />Invested Only</label>
        </div>
    </div>


    <div *ngIf="!FundClasses || !FundClasses.FundDetailsViewModel" style="padding-top:10px">
        <div class="alert alert-warning" style="text-align:center" role="alert">
            Loading... Please Wait
        </div>
    </div>
    <div [ngClass]="{'show': isExpanded}" id="fundClass" class="collapse" role="tabpanel" aria-labelledby="fundClass_heading"
        data-parent="#fundClass" [attr.aria-expanded]="isExpanded">
        <div class="card-body scrollClass" *ngIf="FundClasses && FundClasses.FundDetailsViewModel">

            <table id="FundClass" class="fundClassesTable table-striped">
                <!-- *ngIf="c != 'Buttons1'  && !CanEdit" -->
                <tr *ngFor="let c of FundClasses.FundClassColumnNames">
                    <th class="fixed-side" scope="col" [ngClass]="c != 'Buttons1'? 'tableItem bold' : 'tableItem cellbgcolor'"> {{ c }}</th>

                    <ng-container *ngFor="let fundClass of FundClasses.FundDetailsViewModel let i=index">
                        <ng-container *ngFor="let f of fundClass['FundClassDetailsViewModel'] | keyvalue">

                            <td class="tableItem" style="font-weight: bold" *ngIf="c == 'Fund Name'">
                                {{ f.value.FundName}}
                            </td>
                            <td [attr.id]="'f.value.Id'" class="tableItem"
                                *ngIf="!EditMode[f.value.Id] && c == 'Accounting Class Name'">{{ f.value.Description}}
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="EditMode[f.value.Id] && c == 'Accounting Class Name'"
                                class="tableItem">
                                <input kendoTextBox [(ngModel)]="f.value.Description"
                                    style="width: 284px; height: 29.5px;" />
                            </td>
                            <td class="tableItem" *ngIf="c == 'Class ID'">{{f.value.Id}}</td>
                            <td *ngIf="EditMode[f.value.Id] && c == 'Legal Fund Class'" class="tableItem">
                                <kendo-dropdownlist [(ngModel)]="f.value.LegalFundClassId"
                                    class="form-control  form-control-sm " [data]="fundClass.PrimaryLegalFundClasses"
                                    [filterable]="false" textField="Description" [valuePrimitive]="true"
                                    valueField="Id">
                                </kendo-dropdownlist>
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="!EditMode[f.value.Id] && c == 'Legal Fund Class'"
                                class="tableItem">
                                {{ f.value.LegalFundClassName}}
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="EditMode[f.value.Id] && c == 'Inception Date'"
                                class="tableItem">
                                <kendo-datepicker [format]="'MMM dd, yyyy'" [(ngModel)]="f.value.InceptionDate"
                                    class="form-control  form-control-sm">
                                </kendo-datepicker>
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="!EditMode[f.value.Id] && c == 'Inception Date'"
                                class="tableItem">
                                {{ f.value.InceptionDate | date:"'MMM dd, yyyy"}}
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="EditMode[f.value.Id] && c == 'Invested Amount'"
                                class="tableItem">
                                <input kendoTextBox [(ngModel)]="f.value.InvestedAmount"
                                    style="width: 284px; height: 29.5px;" />
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="!EditMode[f.value.Id] && c == 'Invested Amount'"
                                class="tableItem">
                                {{ f.value.InvestedAmount | number : '.2-2'}}
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="EditMode[f.value.Id] && c == 'Vehicle Type'"
                                class="tableItem">
                                <kendo-dropdownlist [(ngModel)]="f.value.VehicleTypeId"
                                    class="form-control  form-control-sm " [data]="FundClasses.VehicleTypes"
                                    [filterable]="false" textField="Name" [valuePrimitive]="true" valueField="Id">
                                </kendo-dropdownlist>
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="!EditMode[f.value.Id] && c == 'Vehicle Type'"
                                class="tableItem">
                                {{ f.value.VehicleTypeName}}
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="EditMode[f.value.Id] && c == 'Closure Status'"
                                class="tableItem">
                                <kendo-dropdownlist [(ngModel)]="f.value.ClosureStatusId"
                                    class="form-control  form-control-sm" [data]="FundClasses.ClosureStatuses"
                                    [filterable]="false" textField="Name" [valuePrimitive]="true" valueField="Id">
                                </kendo-dropdownlist>
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="!EditMode[f.value.Id] && c == 'Closure Status'"
                                class="tableItem">
                                {{ f.value.ClosureStatusName}}
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="EditMode[f.value.Id] && c == 'Is Side Pocket?'"
                                class="tableItem">
                                <input type="checkbox" value="{{f.value.IsSidePocket}}" id="chkSidePocket"
                                    [(ngModel)]="f.value.IsSidePocket" style="width: 13px; height: 13px;" />
                                <label for="chk">Yes</label>

                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="!EditMode[f.value.Id] && c == 'Is Side Pocket?'"
                                class="tableItem">
                                {{ f.value.IsSidePocket == true ? 'Yes' : 'No'}}
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="EditMode[f.value.Id] && c == 'Is Thematic?'"
                                class="tableItem">
                                <input type="checkbox" value="{{f.value.IsThematic}}" style="width: 13px; height: 13px;"
                                    [(ngModel)]="f.value.IsThematic" />
                                <label for="chkThematic">Yes</label>
                            </td>
                            <td [attr.id]="'f.value.Id'" *ngIf="!EditMode[f.value.Id] && c == 'Is Thematic?'"
                                class="tableItem">
                                {{ f.value.IsThematic == true ? 'Yes' : 'No'}}
                            </td>

                            <td class="tableItem" *ngIf="c == 'Buttons1' && CanEdit">

                                <button *ngIf="!EditMode[f.value.Id]" type="button"
                                    class="btn btn-primary btn mr-1 "
                                    (click)="buttonClicked(f.value.Id)">Edit</button>
                                <button *ngIf="EditMode[f.value.Id]" type="button"
                                    class="btn btn-primary btn mr-1"
                                    (click)="Update(f.value.Id)">Save</button>
                                <button *ngIf="EditMode[f.value.Id]" type="button"
                                    class="btn btn-primary btn mr-1"
                                    (click)="Delete(f.value.Id)">Delete</button>
                                <button *ngIf="EditMode[f.value.Id]" type="button"
                                    class="btn btn-primary btn mr-1"
                                    (click)="buttonClicked(f.value.Id)">Cancel</button>

                            </td>

                        </ng-container>
                    </ng-container>

                </tr>
            </table>
        </div>
    </div>
</div>

Update 1

After applying darthnach's solution, I encountered a minor issue with scrolling where the contents were visible in the margin

css

 th {
        padding: 7px;
        position: sticky;
        left:0;
        min-width: 300px;
        background-color:#f5f7f7;

        }

Screenshot 1 https://i.sstatic.net/H2QXG.png

Screenshot 2 https://i.sstatic.net/m7pJH.png

Here is the stackblitz

stackblitz.com/edit/angular-d1mzew

Update 2

A fix has been implemented to address the border issue during scrolling, however, the text visibility problem persists while scrolling

https://i.sstatic.net/nQvgh.jpg

Answer №1

Expanding on the response from @Sethuraman, by substituting padding with margin and adding a border to the div enclosing the table, it could potentially resolve the border issue you are facing (if that is indeed your concern).

Consider making the following adjustment:

.card-body {
    flex: 1 1 auto;
    padding: 0;
    margin: 10px 0;
    /* border: 1px solid lightgray; */ <-- Feel free to add or remove based on your requirements
}

This showcases the effect before and after applying changes to the aforementioned class.

https://i.sstatic.net/jDooG.png

https://i.sstatic.net/EYBSO.png

Additionally, eliminating border spacing can prevent a 2px scrolling gap on the th elements when scrolling content towards the left.

.fundClassesTable[_ngcontent-xcq-c0] {
    table-layout: fixed;
    border-spacing: 0;
}

Please inform me if this solution proves helpful or if you have any other specific concerns.

Answer №2

Instead of using padding in the .card-body, you can try using margin which might help solve your issue. I tested this solution on stackblitz -- https://stackblitz.com/edit/angular-d1mzew-solution

.card-body {
    flex: 1 1 auto;
    /* padding: 10px; */
    margin: 10px;
}

Answer №3

To achieve this effect, you can try using the CSS properties position:sticky and left:-10px. You can view an example on StackBlitz. I believe this solution will fulfill your requirements.

th{
    position: sticky;
    left: -10px;

}

Answer №4

Feel free to experiment with this code snippet in the initial column.

div {
  overflow-x:scroll;  
  margin-left:6em;
  width: 300px;
    }
table th, td{
  border: 1px solid #000;
}
.first-col {
  position:absolute;
width:6em;
left:0;
  text-align: center;
  background-color: #ccc;
    }
<div>
  <table>
    <thead>
      <tr>
        <th class="first-col">text</th>
        <th>value</th>
        <th>value2
        </th>
        <th>value2
        </th>
        <th>value3
        </th>
        <th>value4
        </th>
        <th>value5
        </th>
        <th>value6
        </th>
        <th>value7
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td class="first-col">lorem ipsum</td>
        <td><strong>0</strong>
        </td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
      </tr>
      <tr>
        <td class="first-col">lorem ipsum</td>
        <td><strong>0</strong>
        </td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
      </tr>
      <tr>
        <td class="first-col">lorem ipsum</td>
        <td><strong>0</strong>
        </td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
      </tr>
      <tr>
        <td class="first-col">lorem ipsum</td>
        <td><strong>0</strong>
        </td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
      </tr>
      <tr>
        <td class="first-col">lorem ipsum</td>
        <td><strong>0</strong>
        </td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
      </tr>
      <tr>
        <td class="first-col">lorem ipsum</td>
        <td><strong>0</strong>
        </td>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
      </tr>
    </tbody>

  </table>

</div>

Answer №5

To resolve the issue, all you need to do is eliminate the position fixed property from 'th' and instead insert the following code:

th {
  position: sticky;
  left:0;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The implementation of async await within a switch case statement is failing to function properly

Is it possible to wait for the resolution of a promise within a switch case statement by using the keyword await? I am facing an issue with my Angular component where the following code is causing crashes in my application. switch (this.status) { ...

What is the process for loading a script file from within a component's HTML?

My goal was to include a specific script file in the component html, but I noticed that when I added the script reference within the html itself, the inner script file was not rendered along with the component on the page. Component import { Component } ...

Manage several scrolls using overflow:auto

There are numerous popups on a page with the overflow:auto property. The structure is as follows - <div id="popup1"> <div>SomeHTMLSTRUC</div> <div>SomeHTMLSTRUC</div> <ul class="scroll"></ul> </div> ...

Is there a way to display a message in a div container instead of using the alert box when there is a successful ajax response?

Hey there, I'm currently working on implementing error validation handling for a custom form that I've created. I'm looking to display the error messages in a designated div rather than using the standard browser alert box. Since I'm fa ...

Tips for creating a responsive div that contains both an image and description, including automatically resizing the image to fit the

#content { background-color: #ACAE4C; float: right; display: inline-block; padding: 0; } <div id="content"> <div class="pic"></div> <div class="desc"></div> </div> I need assistan ...

Is there a way to retrieve the resolved data within the route definition in Angular?

I am looking to execute some actions within the route definition once the lazyloaded module is loaded. The route includes a resolver called UserDataResolverService. How can I retrieve and utilize the resolved data within the route definition? { ...

Creating a dropdown menu utilizing JavaScript/jQuery arrays

Looking to create an HTML select menu using a JavaScript array where the keys are used as values for options. The challenge is when entering numbers as keys, they should be accepted in the code. a([selected="No of rooms", 1="1", 2="2", 3="3", 4="4", 5="5" ...

How to create a thumbnail hover effect with CSS3 and javascript, overcoming the z-axis issue

Currently, I am working on creating a set of thumbnails that enlarge when hovered over. The initial setup achieves the zoom effect using CSS3 transform:scale and ease-in-out. However, the issue is that the enlarged images overlap each other due to sharing ...

How come Font Awesome icons aren't appearing in my link?

Is my question strange? I've noticed a peculiar behavior when using fontawesome. Normally, it displays correctly, and I have already referred to the documentation, but none of the solutions I found here seem to solve my issue. Sources I have tried: ...

The type 'angular' does not have a property of this kind

Having trouble importing a method into my Angular component. An error keeps popping up: Property 'alerta' does not exist on type 'typeof PasswordResetService'. any I've double-checked the code and everything seems to be in order! ...

The color of the progress bar in JS is not displaying properly

My work involves using jQuery to manipulate progress bars. The issue I am facing is defining standard colors that should be displayed on the progress bar based on the value received. Here is my code: var defaultSegmentColors = ['#FF6363', &ap ...

Utilizing Express for hosting public static resources

I am having trouble configuring my Express server to serve files from the public folder. Despite trying various file path combinations, Pug does not seem to cooperate with Node.js. While I can view the HTML content of the index, the CSS and music files fai ...

Conditional formatting for form field styles

Is there a way in Angular to conditionally render a material style? For instance, I am looking to apply the following style only to my Password form field text, and only when both input boxes have content: .mat-form-field-appearance-outline .mat-form-fiel ...

Determine the variable height of a div containing dynamic content in order to execute a transform

Looking to create a dynamic container that expands when a button/link is clicked? The challenge lies in achieving this expansion effect with a smooth transition. By using the height: auto property, the container can expand to fit its content, but incorpora ...

Determining User Consent: A Straightforward Guide to Identifying Previously Accepted Cookie Consent

I've been tasked with adding a cookie to a website. The site only tracks the number of visits, so there is no user-specific data available for cookie assignment or acknowledgment tracking. Is it possible to show the cookie notification only to users ...

Expanding your knowledge of AngularJS: utilizing ng-click to interact with elements

After a user clicks on an element in my app, I have some logic that runs. For example: html <h3 ng-click="showAlert('text')">this is text! (try to click and select)</h3> js $scope.showAlert = function(text) { console.log(' ...

Revamp your search experience with Algolia's Angular Instant Search: Design a personalized search box template

Custom Search Box Request: My goal is to implement an autosuggest search box using Algolia Angular instant search with an Angular Material design. To achieve this, I am planning to customize the search box component by replacing the standard <ais-sea ...

The utilization of .forRoot() in the feature modules hierarchy

Could someone please explain to me the best way to organize a hierarchy of nested feature modules with .forRoot() calls? For instance, let's say I have modules structured like this: - MainModule - SharedModule - FeatureModuleA - FeatureModuleA1 ...

Utilizing CSS in Angular applications

I am currently working on an Angular 2 application and I am fairly new to Angular. I am facing an issue where my CSS does not seem to be applying properly. There are three key files involved: landing.component.html landing.component.scss landing.compone ...

Chrome Bug with Fixed Position Background

Just finished creating a website that features fixed images as backgrounds with text scrolling on top of them. I've noticed an issue when using Chrome - the scrolling stops briefly between backgrounds, pauses for about a second, and then resumes. I&ap ...