HTML Tabelle und Textboxen zueinander ausrichten

Magic1416

Lieutenant
Registriert
Dez. 2003
Beiträge
513
Hallo,

ich bin neu im Thema HTML. Ich entwickele gerade eine Test Seite in ASP Net Core Blazor und habe mir folgende Aufgabenstellung gegeben.

1. Daten aus einer Datenbank abrufen. (erledigt)
2. Daten in einer Tabelle darstellen, wobei die erste Spalte eine Checkbox ist (erledigt)
3. Die Breite der Tabellenspalten dynamisch an die Browserfesnterbreite sinngemäß angepasst (glaub ich, dass das erledigt ist)
4. Über jeder Spalte, mit Ausnahme der ersten Spalte, soll eine Textbox sein und mit Placeholdern versehen sein. Diese Textboxen dienen als Spaltenfilter. Sobald dort Text eingegeben wird, beginnt Blazor mit dem Filtern der Spalten und rendert den Output neu (erledigt)
5. Diese Textboxen sollen an den Spalten der Tabelle bündig ausgerichtet sein. Das bekomme ich einfach nicht hin, obwohl die Werte genauso übernommen wurde, wie in der Datentabelle. Die Textboxen sind irgendwie nie bündig zu den Spalten, egal was ich mache. (Hier brauch ich Unterstützung)
6. Die Textboxen sollen solange bündig zur Datentabelle ausgerichtet sein, bis eine bestimmte, minimale breite der Textbox erreicht wurde (z.B. auf Handys oder wenn man das Browserfenster klein zieht). Ab dann sollen die Textboxen nicht mehr nebeneinander sein, sondern gestapelt werden. (Keine Ahnung wie man das realisieren könnte)

Mein Code sieht folgendermaßen aus:

C#:
@page "/dsm/overview"
@using WebServices.Converter
@using WebServices.DSM
@using WebServices.DSM.Model
@using System.Linq.Expressions
@using System.Linq
@using System.Reflection
@using System.Collections.Generic
@using System.Collections

@inject WebServices.DSM.IDsmService dsmservice

<style>
    .test2 {
        font-size: 120%;
        color: red;
    }
    .test1 {
        padding-left: 0px;
        padding-right: 4px;
    }
</style>


<h3>DSM Overview</h3>





@if (Results == null)
{
    <p><em>loading results. Please wait ...</em></p>

}
else
{
    
    <table class="table table-borderless">
        <tr>
            <th><div style="width:20px"></div></th>
            <th style="padding-left:0px;width:21%"><input value="@FilterName" type="text" class="form-control form-control-sm" placeholder="Name" @onchange="_ => change(() => FilterName,_.Value)" /></th>
            <th style="padding-left:0px;width:25%"><input value="@FilterDesc" type="text" class="form-control form-control-sm" placeholder="Description" @onchange="_ => change(() => FilterDesc,_.Value)" /></th>
            <th style="padding-left:0px;width:6%"><input type="text" class="form-control form-control-sm" placeholder="ID"></th>
            <th style="padding-left:0px;width:14%"><input type="text" class="form-control form-control-sm" placeholder="Date of Publication"></th>
            <th style="padding-left:0px;width:14%"><input type="text" class="form-control form-control-sm" placeholder="Date of Approval"></th>
            <th style="padding-left:0px;width:10%"><input type="text" class="form-control form-control-sm" placeholder="ChangeNumber"></th>
            <th style="padding-left:0px;width:10%"><input type="text" class="form-control form-control-sm" placeholder="Status"></th>
        </tr>

    </table>




    <table class="table table-striped">
        <tr>
            <th></th>
            <th>Name</th>
            <th>Description</th>
            <th>ID</th>
            <th>Date of Publication</th>
            <th>Date of Approval</th>
            <th>ChangeNumber</th>
            <th>Status</th>
        </tr>
        @foreach (var item in FilteredList)
        {
            <tr @key="@item.ID">
                <td><input type="checkbox" ></td>
                <td width="21%">@item.Name</td>
                <td width="25%" style="word-wrap: break-word">@item.Description</td>
                <td width="6%">@item.ID</td>
                <td width="14%">@item.DateOfPublication?.ToString("dd.MM.yyyy HH:mm")</td>
                <td width="14%">@item.DateOfApproval</td>
                <td width="10%">@item.ChangeNumber</td>
                <td width="10%">@item.Status</td>
            </tr>
        }

    </table>


}


@code {

    public string FilterName { get; set; }
    public string FilterDesc { get; set; }

    void change<T>(Expression<Func<T>> memberExpression,object newVal)
    {
        (string membername, object value) = ExpressionHelper.GetKeyValue(memberExpression);

        var prop = this.GetType().GetProperty(membername);
        prop.SetValue(this, newVal);



        FilteredList = applyFilter().ToList();
        StateHasChanged();


    }

    IEnumerable<DSMViewModel> applyFilter()
    {
        var result = new List<DSMViewModel>();

        DSMViewModel[] arr = new DSMViewModel[Results.Count];
        Results.CopyTo(arr);

        IEnumerable<DSMViewModel> results = (IEnumerable<DSMViewModel>)arr;

        bool l_validate(string value,string filter)
        {
            if (string.IsNullOrWhiteSpace(value)) return false;
            return value.Contains(filter, StringComparison.OrdinalIgnoreCase);
        }

        if (!string.IsNullOrWhiteSpace(FilterName))
            results = results.Where(item => l_validate(item.Name, FilterName));

        if (!string.IsNullOrWhiteSpace(FilterDesc))
            results = results.Where(item => l_validate(item.Description, FilterDesc));
      
        return results;
    }


    public List<DSMViewModel> Results;
    public List<DSMViewModel> FilteredList;
    public string Filter { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await dsmservice.ConnectAsync();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            //Get items from DSM
            var results = await dsmservice.Get_DSMResultAsync(null, "Prod");

            //Initialize Result list
            if (Results == null)
            {
                Results = new List<DSMViewModel>();
                Results = results.OrderBy(items => items.Name).ToList();
            }

            //Add to result array           
            FilteredList = Results;

            //Trigger a change
            StateHasChanged();
        }
    }


}

Und so siehts aus
bild1.JPG


Und hier ungestapelt
bild2.JPG


Vielen Dank für Eure Hilfe
Gruß Magic
 
Ich würde überhaupt nicht mit einer Tabelle arbeiten sondern mit Flexbox bzw. bestenfalls sogar mit CSS Grid, wenn nicht gerade Uralt-Browser unterstützt werden sollen.
 
Das ist doch eine Tabelle, wieso hier mit Flexbox? Welchen Vorteil versprichst du dir davon?
 
@Tourgott Nein, das ist eindeutig eine Tabelle, also gehörts da auch rein. Hört auf Tabellen für tabellarische Daten zu ersetzen, nur weil Tabellen als Layoutmittel missbraucht wurden.

@Magic1416 Warum erstellst du zwei Tabellen? Ist doch klar, dass das nix wird.
 
  • Gefällt mir
Reaktionen: kim88, GroMag und savuti
Yuuri schrieb:
@Tourgott Nein, das ist eindeutig eine Tabelle, also gehörts da auch rein. Hört auf Tabellen für tabellarische Daten zu ersetzen, nur weil Tabellen als Layoutmittel missbraucht wurden.
Er sucht nach einer responsive Lösung. Das wird mit dieser Tabelle nahezu unmöglich sein. Warum sich das Leben also schwer machen?
 
Tourgott schrieb:
Er sucht nach einer responsive Lösung. Das wird mit dieser Tabelle nahezu unmöglich sein.
Sagt wer?
Es gibt genug Möglichkeiten Tabellen problemlos responsive darzustellen. Ob da nun <div> oder <td> steht, ist dem CSS doch egal. Aber eine Tabelle ist eine Tabelle. Und Buttons sind auch keine Links, die wie Buttons aussehen. Screenreader danken dir.
 
  • Gefällt mir
Reaktionen: GroMag, savuti und floq0r
Ja wenn man aus der Tabelle etwas macht, das keine Tabelle mehr ist dann geht das natürlich :D
Ich hab z.B. Lösungen wo ich für mobile devices aus einer Tabelle ein grid mache und den tbody tag dazwischen über display: contents; "deaktiviere".
 
Yuuri schrieb:

Noch mal: Warum sich das Leben schwer machen, wenn es auch wesentlich einfacher geht? Man muss nicht zwanghaft an Altem festhalten, nur weil man nicht aufgeschlossen gegenüber etwas Neuem ist.
 
  • Gefällt mir
Reaktionen: KitKat::new()
Yuuri schrieb:
@Magic1416 Warum erstellst du zwei Tabellen? Ist doch klar, dass das nix wird.

Wie gesagt ist mir html-Gestaltung ziemlich neu. Ich suche mich im Web gerade zu Tode. das Problem dabei ist, dass mir zu meinen Ideen oft der Fachbegriff hinter der passenden Form oder der entsprechenden Technik fehlt. Das führt in Google nicht oft zum Ziel. Der Gedanke mit den zwei Tabellen ist folgender: Ich formatiere die Spalten in beiden Tabellen identisch und ich sollte auch ein optisch identisches Ergebnis erzielen. Das ist aber nicht der Fall. Außerdem interessieren auch manchmal die Formatierungen nicht, die ich setze. z.B. eine feste Weite bei der Checkbox Spalte. Das macht er einfach nicht. Nur prozentual geht. Das schaut aber doof aus. die Elemente stapeln beim Kleinziehen funktioniert mit der Tabelle wiederum garnicht. Also hab ich jetzt mal die erste Tabelle durch folgendes ersetzt:


HTML:
<style>   
    .test1 {
        margin-left: 0px;
        margin-right: 4px;
        margin-bottom: 2px;
        margin-top: 2px;
    }
</style>

<div style="width:100%;padding-bottom:20px">
    
<form action="" class="form-inline">
        <input value="@FilterName" type="text" class="form-control form-control-sm test1" placeholder="Name" @onchange="_ => change(() => FilterName,_.Value)" />
        <input value="@FilterDesc" type="text" class="form-control form-control-sm test1" placeholder="Description" @onchange="_ => change(() => FilterDesc,_.Value)" />
        <input type="text" class="form-control form-control-sm test1" placeholder="ID">
        <input type="text" class="form-control form-control-sm test1" placeholder="Date of Publication">
        <input type="text" class="form-control form-control-sm test1" placeholder="Date of Approval">
        <input type="text" class="form-control form-control-sm test1" placeholder="ChangeNumber">
        <input type="text" class="form-control form-control-sm test1" placeholder="Status">
    </form>
</div>

Jetzt stapelt er die Elemente beim Kleinziehen wie gewollt. Dafür sind die Elemente wiederum garnicht mit der Tabelle alligned. Ich versuche gerade irgendwie, jedes einzelne Element exakt über einer Spalte der Tabelle zu platzieren.
Ich kann nicht mal sagen, ob das der richtige Weg ist. Denn ein nächster Schritt soll ein kleiner Button sein, der den Filter ein- und ausblendet. So ähnlich wie eine RibbonBar in einer Anwendung.
Ergänzung ()

Tourgott schrieb:
Ich würde überhaupt nicht mit einer Tabelle arbeiten sondern mit Flexbox bzw. bestenfalls sogar mit CSS Grid, wenn nicht gerade Uralt-Browser unterstützt werden sollen.

Flexbox kenne ich noch nicht und kam mir bisher auch nicht bei meiner Recherche unter.
 
Pack die Ausgabe in eine Tabelle und nicht in zwei. Dann hast du alles in der jeweiligen gleichen Spalte.

Code:
    <table class="table table-borderless">
        <tr class="head_1">
            <th><div style="width:20px"></div></th>
            <th style="padding-left:0px;width:21%"><input value="@FilterName" type="text" class="form-control form-control-sm" placeholder="Name" @onchange="_ => change(() => FilterName,_.Value)" /></th>
            <th style="padding-left:0px;width:25%"><input value="@FilterDesc" type="text" class="form-control form-control-sm" placeholder="Description" @onchange="_ => change(() => FilterDesc,_.Value)" /></th>
            <th style="padding-left:0px;width:6%"><input type="text" class="form-control form-control-sm" placeholder="ID"></th>
            <th style="padding-left:0px;width:14%"><input type="text" class="form-control form-control-sm" placeholder="Date of Publication"></th>
            <th style="padding-left:0px;width:14%"><input type="text" class="form-control form-control-sm" placeholder="Date of Approval"></th>
            <th style="padding-left:0px;width:10%"><input type="text" class="form-control form-control-sm" placeholder="ChangeNumber"></th>
            <th style="padding-left:0px;width:10%"><input type="text" class="form-control form-control-sm" placeholder="Status"></th>
        </tr>
        <tr class="head_2">
            <th></th>
            <th>Name</th>
            <th>Description</th>
            <th>ID</th>
            <th>Date of Publication</th>
            <th>Date of Approval</th>
            <th>ChangeNumber</th>
            <th>Status</th>
        </tr>
        @foreach (var item in FilteredList)
        {
            <tr @key="@item.ID">
                <td><input type="checkbox" ></td>
                <td width="21%">@item.Name</td>
                <td width="25%" style="word-wrap: break-word">@item.Description</td>
                <td width="6%">@item.ID</td>
                <td width="14%">@item.DateOfPublication?.ToString("dd.MM.yyyy HH:mm")</td>
                <td width="14%">@item.DateOfApproval</td>
                <td width="10%">@item.ChangeNumber</td>
                <td width="10%">@item.Status</td>
            </tr>
        }

    </table>

So ungefähr...

Tourgott schrieb:
Noch mal: Warum sich das Leben schwer machen, wenn es auch wesentlich einfacher geht? Man muss nicht zwanghaft an Altem festhalten, nur weil man nicht aufgeschlossen gegenüber etwas Neuem ist.

Und dann willst du die einzelnen Spalten untereinander positionieren? Das ist nicht der Sinn einer Tabelle. Wenn dann macht man das horizontal "scrollbar". Bei Content-Elementen geht, im Moment, nichts an Flexbox vorbei, keine Frage. Die Inhalte einer Tabelle sind keine Content-Elemente, sondern die Tabelle ist ein Content-Element.
 
  • Gefällt mir
Reaktionen: Magic1416 und GroMag
Tourgott schrieb:
Warum sich das Leben schwer machen, wenn es auch wesentlich einfacher geht? Man muss nicht zwanghaft an Altem festhalten, nur weil man nicht aufgeschlossen gegenüber etwas Neuem ist.
Was ist an Tabellen alt? Tabellen sind eine semantische Struktur, daran ist nichts "alt". Flexbox organisiert die Daten nicht als Tabelle, sondern stellt es in gewünschter Ansicht dar. Grids sind ebenso fürs Layout. Tabellen wurden damals nur zum Layout zweckentfremdet, weil CSS nicht den Umfang von heute hatte.

Ich kann auch eine Schraube in die Wand hämmern, da halt moderner und ich ja "aufgeschlossen gegenüber Neuem" bin. Kann ich machen, ist halt Scheiße. Jeder, der dich beim Hämmern von Schrauben sieht, wird gewiss einen Kommentar da lassen.
floq0r schrieb:
Ja wenn man aus der Tabelle etwas macht, das keine Tabelle mehr ist dann geht das natürlich
Ja, dafür ist das HTML-Element aber nicht gemacht bzw. ist es historisch bedingt eben so, dass <table> klassisch in Tabellenform dargestellt wird, weil HTML seit 1992 existiert, während CSS erst 1996 erfunden wurde und wirkliche "Layouts" quasi erst in den letzten Jahren mit CSS 3 umgesetzt werden können.

https://medium.com/appnroll-publica...s-to-make-responsive-data-tables-ff031c48b122

1602149977822.png

1602150062444.png

Der Vorteil ist eben, dass etwas semantisch korrekt umgesetzt wird (als Quelle von unterschiedlichen Daten), die Darstellung auf unterschiedlichsten Geräten oder gar nur bei unterschiedlichen Verwendungszwecken oder Ansichten allerdings komplett anders geregelt werden kann.

Tabellarische Daten, die nicht nur auf eine klassische "Darstellung als Tabelle" fixiert sind:

1602150390910.png1602150410067.png1602150422364.png1602150433180.png1602150443908.png

Das realisiert man problemlos via CSS mit ner simplen Datentabelle im Hintergrund, die man entsprechend der eingestellten Ansicht unterschiedlich darstellt. Ja, in einer Ansicht ist es offensichtlich eine Tabelle, in der Anderen eine Liste. Semantisch betrachtet sind es trotzdem tabellarischen Daten, auch wenn sich die Darstellung unterscheidet. Überhaupt erst so lässt sich etwas responsive ohne Duplicate Content und ohne JavaScript-Gefummel via JQuery, Vue, Angular, React und Co. umsetzen, wo SEO und Screenreader glücklich sind und $Suchmaschine Content entsprechend extrahieren, darstellen und filtern kann. Wenn du das als stupide div-Suppe mit Flexbox garniert umsetzt, können $Suchmaschine entsprechend nicht mehr den Content exakt als das filtern, wie es eigentlich gedacht war. Als Auflistung/Ansammlung/Gegenüberstellung/whatever von Daten. Wenn eine Smartwatch standardmäßig eine Tabelle nur mit der erstlängsten Spalte darstellt und die restlichen Spalten als Dropdown-Liste. Who cares? Genau deshalb kann die Smartwatch das, weil sie eben weiß, dass es tabellarische Daten sind. Würde ich dort hunderte `<div>`s platzieren, käme kompletter Murks raus.

Und wenn du die Explorer-Ansicht oben nicht als "Tabelle" darstellen würdest, würdest du spätestens bei der Darstellung als Liste die Daten trotzdem aus einer Datatable ziehen. Den Sinn versteht man, oder?

Anderes, einfaches Beispiel:

Sehen wir uns mal den CB RSS-Feed an: https://www.computerbase.de/rss/news.xml
Code:
<entry>
    <title>Turtle Beach Stealth 600 G2 im Test: Stabiles Funk-Headset für 100 Euro</title>
    <link rel="alternate" type="text/html" href="https://www.computerbase.de/2020-10/turtle-beach-stealth-600-gen-2-test-guenstiges-funk-headset-kompromisse/" />
    <id>tag:computerbase.de,2020:artikel-73762</id>
    <published>2020-10-08T12:00:00+02:00</published>
    <updated>2020-10-08T12:00:00+02:00</updated>
    <summary type="html"><![CDATA[<img src="https://pics.computerbase.de/9/5/1/7/8/article-630x354.593e745d.jpg"><p>tl;dr: Mit dem Stealth 600 der zweiten Generation will Turtle Beach mit einem UVP von unter 100 Euro einen günstigen Einstieg in die Welt der Funk-Headsets bieten, erkauft sich den Preis aber mit Kompromissen bei der Materialwahl, dem Klang und vor allem der Mikrofonqualität.</p>]]></summary>
   
    <author>
        <name>Michael Schäfer</name>
    </author>
    <category term="Audio/Video/Foto" scheme="https://www.computerbase.de/thema/audio-video-foto/" />
</entry>
<entry>
    <title>Android 11 und 10: Updates für Smartphones mit Stand 10/2020 im Überblick (Update)</title>
    <link rel="alternate" type="text/html" href="https://www.computerbase.de/2018-09/android-updates-smartphones-ueberblick/" />
    <id>tag:computerbase.de,2018:artikel-64301-1602148380</id>
    <published>2018-09-06T12:00:00+02:00</published>
    <updated>2020-10-08T11:13:00+02:00</updated>
    <summary type="html"><![CDATA[<img src="https://pics.computerbase.de/8/3/8/0/8/article-630x354.b69cae1a.jpg"><p>Android-Updates bestimmen den Kauf eines Smartphones und die Wertschätzung des Herstellers wie kaum ein anderes Thema. Eine Übersicht der zur Verfügung stehenden Updates gibt es häufig nicht beim Hersteller. ComputerBase sorgt aus diesem Grund mit einem tabellarischen Überblick der wichtigsten Marken und Modelle für Aufklärung.</p>]]></summary>
   
    <author>
        <name>Nicolas La Rocco</name>
    </author>
    <category term="Betriebssystem" scheme="https://www.computerbase.de/thema/betriebssystem/" />
</entry>
<entry>
    <title>Mafia: Definitive Edition: Update bringt Schwarzweiß-Noir-Modus [Notiz]</title>
    <link rel="alternate" type="text/html" href="https://www.computerbase.de/2020-10/mafia-definitive-edition-update-noir-modus/" />
    <id>tag:computerbase.de,2020:artikel-73888</id>
    <published>2020-10-08T11:06:00+02:00</published>
    <updated>2020-10-08T11:06:00+02:00</updated>
    <summary type="html"><![CDATA[<img src="https://pics.computerbase.de/9/5/3/3/3-908fe9dffbd15e7b/article-630x354.4b572e12.jpg"><p>Neben obligatorischen Fehlerbehebungen erhält das erst kürzlich erschiene Mafia: Definitive Edition mit dem ersten großen Update unter anderem einen optionalen „Noir“-Grafikmodus, der das gesamte Spiel in Schwarzweiß mitsamt Filmkorn-Effekt hüllt.</p>]]></summary>
   
    <author>
        <name>Jan Lehmann</name>
    </author>
    <category term="Games" scheme="https://www.computerbase.de/thema/games/" />
</entry>
Das ist eine Struktur mit tabellarischen Daten.

Und wie sieht es im Browser aus?
1602151841095.png


Oh, keine "Tabelle" oder Liste oder sonstwas. Genau dafür ist eben eine unterschiedliche Darstellungsform da, in welche Kategorie eben Flexbox und Grid und sonstiger Kram fällt, was genau der Aufgabe von CSS entspricht. Im Hintergrund ist trotzdem eine Auflistung von Daten die Quelle. Deshalb verwendet man dafür auch <table> im HTML und nicht <div>. Es gibt auch <dl> für Datenlisten, das ist aber nur ein simpler Key-Value-Store.
Magic1416 schrieb:
Wie gesagt ist mir html-Gestaltung ziemlich neu. Ich suche mich im Web gerade zu Tode.

Ein Tipp: Wenn du Anderen etwas zeigen willst, nimm am besten für ein kurzes Minimalbeispiel Dienste wie jsfiddle, CodePen, o.ä.

Warum hast du die Tabelle aufgelöst? Du hättest die zwei Tabellen einfach nur verbinden müssen.

Ganz simples Beispiel runtergebrochen: https://jsfiddle.net/Lnfhsb3d/

Bis 800 px Größe werden die Spalten untereinander gestackt. Aber die Darstellung regelst du dann übers CSS und nicht mehr über das HTML.

Etwas responsive und Styling dazu, auch etwas Flexbox: https://jsfiddle.net/Lnfhsb3d/1/

Wie du es für dich dann am besten darstellst, musst du dann eben anhand deiner Daten probieren.
 
  • Gefällt mir
Reaktionen: Magic1416 und netzgestaltung
Tourgott schrieb:
https://medium.com/evodeck/responsive-data-tables-with-css-grid-3c58ecf04723

Na hauptsache du schraubst weiter deine Schrauben während andere dir davon nageln.
Was willst du mir damit sagen? Dass du nen Artikel gefunden hast, der das CSS Grid zweckentfremdet um Tabellen darzustellen? Soll ich dir jetzt ein Tutorial von 2000 posten die Tabellen zum Seitenlayout verwenden oder was willst du mit der Aussage erreichen?

CSS Grids sind fürs Layout zuständig. Punkt.
https://www.w3.org/TR/css-grid-1/ schrieb:
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design.
Was natürlich nicht heißt, dass ich ein Grid nicht für Tabellen nutzen kann. Es wird einfach nur zweckentfremdet.

Grid für Masonry Layouts: https://www.bram.us/2020/05/04/css-grid-layout-module-level-2-masonry-layout/
Full Bleed Layout: https://joshwcomeau.com/css/full-bleed/
etwas mehr Beispiele: https://gridbyexample.com/examples/

Zeig mir beim letzten Beispiel doch mal, wo das Wort "Tabelle" auftaucht.

Noch ein schöner Ted Talk:

 
Yuuri schrieb:
Dass du nen Artikel gefunden hast, der das CSS Grid zweckentfremdet um Tabellen darzustellen?
Genauso wie du einen Artikel gefunden hast, der Tabellen zweckentfremdet? So kann man natürlich auch argumentieren.
 
Habe ich diese Diskussion gerade ernsthaft gelesen?

@Magic1416 ich hoffe dein Problem wurde gelöst.

@Tourgott natürlich kannst du mit <divs> und Flexbox, CSS Grid und wenn einem ganz langweilig ist auch mit floats Elemente im Frontend zeichnen die wie eine Tabelle aussehen.

Es ist aber nicht sinnvoll das zu tun und ich nenne dir da gerne zwei Gründe und einer davon liegt mir am Herzen:

Herzensgrund: Barrierefreiheit

Viele Menschen in unserer Gesellschaft haben körperliche Einschränkungen, sie sind z.B. Blind. Auch diese Menschen benutzen das Internet - jeden Tag und so häufig wie wir. In der Regel mit zusätzliche Software wie speziellen Screen-Readern.

Diese Software kann kein CSS auslesen und Gestaltung interpretieren. Die richtet sich nach dem Quelltext. Deswegen ist die Semantik sehr wichtig. Wenn es im Quelltext ein <table>, <thead>, <th>, <tbody>, <td>, etc gibt, wiessen diese Screenreader - ah hier ist eine Tabelle. Der Blinde kann das ganz bewusst steuern - "Lies mir bitte Zeile 5 aus dieser Tabelle vor", etc. Was eben nicht funktioniert, wenn das nur verschachtelte Div Container sind.

Der zweite Grund: SEO
Die Suchmaschinen von Google & Co interpretieren ebenfalls kein CSS. Wenn man möchte, dass die eigenen Seite eine gute Platzierung bei den Suchmaschinen hat, ist korrektes HTML neben gutem Content das wichtigste.

Aus diesen Gründen sollte man Tabellen eben nicht für Layouts und ein <div> Konstrukt mit CSS Grid nicht für Tabellen nutzen - auch wenn es von der Optik her natürlich möglich ist.
 
  • Gefällt mir
Reaktionen: GroMag und netzgestaltung
Hallo,

ich möchte mich als erstes bei Euch für die rege Diskussion und die ausführlichen Erklärungen und hilfreichen Links bedanken. Ganz besonders @Yuuri und @savuti . Das hat mir wirklich weitergeholfen.
Ich war die letzten zwei Tage damit beschäftigt, mich weiter in das Thema hineinzuarbeiten und die Seite sowie den Service dahinter zu verbessern. Ein zuerst scheinbar kleines Problem beim Registrieren des Services mittels Dependency Injection entpuppte sich als großes Problem welches eine größere Umstellung erforderte. Die optischen Probleme konnte ich dank Eurer Hilfe lösen. Ist eigentlich ganz einfach gewesen, wenn man halt weiß, wie. Zusätzlich lässt sich der Filter mittels Toggle Button ein- und ausblenden.
Meine nächste Aufgabe ist ein modaler Dialog, welcher erscheinen soll, wenn man einen Button drückt. Dort gibts dann ein paar Felder auszufüllen. Das Ausgefüllte wird dann auf alle selektierten Objekte angewendet, so der Plan.

Der Code sieht folgendermaßen aus:


C#:
@page "/dsm/patchpolicies"
@using WebServices.Converter
@using WebServices.DSM
@using WebServices.DSM.Model
@using System.Linq.Expressions
@using System.Linq
@using System.Reflection
@using System.Collections.Generic
@using System.Collections

@inject WebServices.DSM.IDsmService dsmservice

<style>   
    .col-check {
        width: 20px;
    }

    .col-name {
        padding-left:0px;
        width: 21%;
    }

    .col-desc {
        width: auto;
    }

    .col-id {
        width: 80px;
    }

    .col-dateofpub {
        width: 14%;
    }

    .col-dateofappr {
        width: 14%;
    }

    .col-changenr {
        width: 10%;
    }

    .col-state {
        width: 10%;
    }

    .row-headers {
        border-bottom: 2px solid black
    }

    .row-data:hover {
        background: rgba(24,154,211,.2);
    }
</style>

<h3>DSM Patch Policy Overview</h3>
<p>@dsmservice.ID</p>

@if (DBResults == null)
{
    <p><em>loading patch policy results. Please wait ...</em></p>
}
else
{   
<p style="text-align:right"><a href="" @onclick="@OnToggleFilter" @onclick:preventDefault>Toggle Filter</a></p>
    <table class="table table-borderless">
        <thead>
            @if (filterVisible)
            {
                <tr class="row-filters">
                    <th class="col-filter col-filter-check"></th>
                    <th class="col-filter col-filter-name"><input value="@FilterName" type="text" class="form-control form-control-sm" placeholder="Name" @onchange="_ => change(() => FilterName, _.Value)" /></th>
                    <th class="col-filter col-filter-desc"><input value="@FilterDesc" type="text" class="form-control form-control-sm" placeholder="Description" @onchange="_ => change(() => FilterDesc, _.Value)" /></th>
                    <th class="col-filter col-filter-id"><input type="text" class="form-control form-control-sm" placeholder="ID"></th>
                    <th class="col-filter col-filter-dateofpub"><input type="text" class="form-control form-control-sm" placeholder="Date of Publication"></th>
                    <th class="col-filter col-filter-dateofappr"><input type="text" class="form-control form-control-sm" placeholder="Date of Approval"></th>
                    <th class="col-filter col-filter-changenr"><input type="text" class="form-control form-control-sm" placeholder="ChangeNumber"></th>
                    <th class="col-filter col-filter-state"><input type="text" class="form-control form-control-sm" placeholder="Status"></th>
                </tr>
            }
            <tr class="row-headers">
                <th class="col-header col-header-check"></th>
                <th class="col-header col-header-name">Name</th>
                <th class="col-header col-header-desc">Description</th>
                <th class="col-header col-header-id">ID</th>
                <th class="col-header col-header-dateofpub">Date of Publication</th>
                <th class="col-header col-header-dateofappr">Date of Approval</th>
                <th class="col-header col-header-changenr">ChangeNumber</th>
                <th class="col-header col-header-state">State</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in FilteredList)
            {
                <tr class="row-data" @key="@item.ID">
                    <td class="col-check"><input type="checkbox"></td>
                    <td class="col-name">@item.Name</td>
                    <td class="col-desc" style="word-wrap:break-word">@item.Description</td>
                    <td class="col-id">@item.ID</td>
                    <td class="col-dateofpub">@item.DateOfPublication?.ToString("dd.MM.yyyy HH:mm")</td>
                    <td class="col-dateofappr">@item.DateOfApproval?.ToString("dd.MM.yyyy HH:mm")</td>
                    <td class="col-changenr">@item.ChangeNumber</td>
                    <td class="col-state">@item.Status</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {

    public string FilterName { get; set; }
    public string FilterDesc { get; set; }

    void change<T>(Expression<Func<T>> memberExpression, object newVal)
    {
        (string membername, object value) = ExpressionHelper.GetKeyValue(memberExpression);

        var prop = this.GetType().GetProperty(membername);
        prop.SetValue(this, newVal);

        FilteredList = applyFilter().ToList();
        StateHasChanged();
    }

    /// <summary>
    /// Toggle Filter Button Event
    /// </summary>
    void OnToggleFilter()
    {
        //Invert boolean
        filterVisible = !filterVisible;

        //Trigger a change
        StateHasChanged();
    }
    private bool filterVisible { get; set; }

    /// <summary>
    /// Apply filter
    /// </summary>
    /// <returns></returns>
    IEnumerable<DsmViewModel> applyFilter()
    {
        //Create a copy DBResults
        DsmViewModel[] arr = new DsmViewModel[DBResults.Count];
        DBResults.CopyTo(arr);

        //Cast to IEnumerable
        IEnumerable<DsmViewModel> results = (IEnumerable<DsmViewModel>)arr;

        //local method to validate where clause
        bool l_validate(string value, string filter)
        {
            if (string.IsNullOrWhiteSpace(value)) return false;
            return value.Contains(filter, StringComparison.OrdinalIgnoreCase);
        }

        //Check Filter Name
        if (!string.IsNullOrWhiteSpace(FilterName))
            results = results.Where(item => l_validate(item.Name, FilterName));

        //Check Filter Description
        if (!string.IsNullOrWhiteSpace(FilterDesc))
            results = results.Where(item => l_validate(item.Description, FilterDesc));

        //... and so on....

        //Return
        return results;
    }

    /// <summary>
    /// Connect to Service on initialize
    /// </summary>
    /// <returns></returns>
    protected override async Task OnInitializedAsync()
    {
        await dsmservice.ConnectAsync();
    }

    /// <summary>
    /// Get Data after rendering
    /// </summary>
    /// <param name="firstRender"></param>
    /// <returns></returns>
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            //Initialize Result list
            if (DBResults == null)
            {
                //Get items from DSM
                var results = await dsmservice.Get_PatchPolicyResultAsync(null, "Prod");

                DBResults = new List<DsmViewModel>();
                DBResults = results.OrderBy(items => items.Name).ToList();
            }

            //Assign to result array
            FilteredList = DBResults;

            //Trigger a change
            StateHasChanged();           
        }
    }
    public List<DsmViewModel> DBResults;
    public List<DsmViewModel> FilteredList;   
}

Und so siehts aus
bild3.JPG
 
Sieht gut aus.

Leg um die Tabelle noch nen <div>

HTML:
<div class="table-wrapper">
  <table class="table table-borderless">
    …
  </table>
</div>

CSS:
.table-wrapper {
  width: 100%;
  overflow-y: auto;
  margin: 0 0 1em;
}

.table-wrapper::-webkit-scrollbar {
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
}

.table-wrapper::-webkit-scrollbar-thumb {
  border-radius: 10px;
  border: 5px solid #fff;
  background-color: #333;
}

Dann hast du es auch halbwegs responsive...
 
Zurück
Oben