Pole tekstowe do wprowadzania tekstu HTML o szerokości 100% przepełnia komórki tabeli

106

Czy ktoś wie, dlaczego elementy wejściowe o szerokości 100% przekraczają granicę komórek tabeli.

W prostym przykładzie poniżej pole wprowadzania danych przekracza granicę komórek tabeli, wynik jest okropny. Zostało to przetestowane i dzieje się tak samo na: Firefox, IE7 i Safari.

Czy to ma dla ciebie sens? Czy czegoś mi brakuje, czy wiesz o możliwym rozwiązaniu?

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
<html><head>    
   <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <!-- don't use closing slash in meta tag, it breaks HTML4.01 transitional -->
   <title>Test input text in table</title>
   <style type="text/css">      
      table {border-top: 1px solid #ff0000; border-left: 1px solid #ff0000;}
      table td {border-right: 1px solid #00ff00; border-bottom: 1px solid #00ff00;}
      input[type="text"] {width: 100%;} /* removing this would make input not to go over cells border, but they would be too short, I want them to fit cells size */
   </style>    
</head><body>

<table cellpadding="0" cellspacing="0">
   <tr>
      <td><p>column one hello babe babe babe</p></td>
      <td><p>column two hello babe more</p></td>
      <td><p>column three hello babe more and more</p></td>
   </tr>
   <tr>
      <td><input type="text" value="test"></td>
      <td><input type="text" value="test"></td>
      <td><input type="text" value="test"></td>
   </tr>
</table>

</body></html>
Marco Demaio
źródło
1
Sugerowałbym, że jeśli używasz tylko tabeli do prezentacji danych wejściowych, możesz przełączyć się na używanie a formz labels i inputs wewnątrz ullub ol. co jest przynajmniej nieco bardziej semantyczne. Z pewnością jednak powinieneś używać a form, nawet jeśli trzymasz się table.
David mówi, że przywróć Monikę

Odpowiedzi:

216

Możesz użyć box-sizingwłaściwości CSS3, aby dołączyć zewnętrzne wypełnienie i obramowanie:

input[type="text"] {
     width: 100%; 
     box-sizing: border-box;
     -webkit-box-sizing:border-box;
     -moz-box-sizing: border-box;
}
pricco
źródło
1
To smutne, ale niestety IE 7 nie radzi sobie poprawnie z rozmiarami pudełek. Spróbuj tego w IE 7 ... css3.info/preview/box-sizing lub zobacz css-tricks.com/box-sizing
AnthonyVO
@AnthonyVO: prawda, jedynym obejściem dla IE7 jest dodanie dla niego określonego CSS za pomocą komentarzy warunkowych IE <!--[if lt IE 8]>iinput[type="text"] {width:95%}
Marco Demaio,
24

Wartość szerokości nie uwzględnia obramowania ani dopełnienia:

http://www.htmldog.com/reference/cssproperties/width/

Otrzymujesz 2 piksele wypełnienia z każdej strony plus 1 piksel krawędzi z każdej strony.
100% + 2 * (2 piksele + 1 piksel) = 100% + 6 piks., Czyli więcej niż 100% zawartości podrzędnej, jaką posiada rodzic td.

Masz możliwość:

  • Albo ustawienie box-sizing: border-box;zgodnie z odpowiedzią @ pricco ;
  • Lub używając marginesu 0 i dopełnienia (unikając dodatkowego rozmiaru).
ANeves
źródło
w odpowiedzi na pytanie Sr pts możesz ustawić dopełnienie i obramowanie na 0px, wtedy 100% powinno działać.
Mauro
Rzeczywiście, nawet bez ustawiania jakiegokolwiek dopełnienia dla td - bardzo dobrze dodane.
ANeves
1
Ponadto, jeśli dopełnienie powoduje problem, można użyć text-indentdo symulacji dopełnienia przed wiodącą krawędzią tekstu i line-heightdopełnienia pionowego (chociaż zachowanie dopełnienia pionowego i tak nie wpłynęłoby na szerokość).
David mówi, że przywróć Monikę
14

Problem z takimi rzeczami width:95%;polega na tym, że nie wyglądają dobrze w szerokich, elastycznych układach (ponieważ 5% może wtedy wynosić około 30 pikseli).

U mnie bardzo dobrze sprawdzają się następujące rozwiązania (testowane w Firefoksie, IE 9, Safari):

<table style="background-color: blue; width: 100%;" cellpadding="0" cellspacing="0">
<tr>
    <td style="background-color: red;   padding: 3px;">
        <div style="margin-right: 3px;">
            <div style="padding-right: 3px;">
                <input type="text" style="width:100%;">
            </div>
        </div>
    </td>
    <td style="background-color: purple;   padding: 3px;">
        <div style="margin-right: 3px;">
            <div style="padding-right: 3px;">
                <input type="text" style="width:100%;">
            </div>
        </div>
    </td>
    <td style="background-color: green;   padding: 3px;">
        <div style="margin-right: 3px;">
            <div style="padding-right: 3px;">
                <input type="text" style="width:100%;">
            </div>
        </div>
    </td>
</tr>
</table>

(dodano kolory, aby łatwiej było zauważyć prawidłowe wypełnienie)

Sztuczka polega na owinięciu danych wejściowych dwoma elementami div, zewnętrzna ma margines 3px (co czyni ją o 3px mniejszą niż td), wewnętrzna ma dopełnienie 3px. To sprawia, że ​​wejście o 6 pikseli jest mniejsze niż td, czyli właśnie od tego chciałeś zacząć.

Nie jestem pewien co do mechaniki tego, ale działa.

W tym prostym przykładzie działa również tylko z jednym elementem div z prawym marginesem 6. Jednak w przypadku mojej aplikacji internetowej działa tylko powyższe rozwiązanie.

<table style="background-color: blue; width: 100%;" cellpadding="0" cellspacing="0">
<tr>
    <td style="background-color: red;   padding: 3px;">
        <div style="margin-right: 6px;">
                <input type="text" style="width:100%;">
        </div>
    </td>
    <td style="background-color: purple;   padding: 3px;">
        <div style="margin-right: 6px;">
                <input type="text" style="width:100%;">
        </div>
    </td>
    <td style="background-color: green;   padding: 3px;">
        <div style="margin-right: 6px;">
                <input type="text" style="width:100%;">
        </div>
    </td>
</tr>
</table>
Andreas
źródło
To działa (+1). O dziwo, wstawiłem trochę tekstu przed każdym <input> i dodałem „white-space: nowrap”, aby zachować je w tej samej linii, a następnie trzy <inputs> przepełniły komórki tabeli, jeśli usunę „white-space: nowrap” wszystko znowu działa. Dziwne.
Jose Manuel Abarca Rodríguez
8

Problem został wcześniej wyjaśniony, więc tylko powtórzę: szerokość nie uwzględnia obramowania i wypełnienia. Jedną z możliwych odpowiedzi na to pytanie, które nie zostało omówione, ale która okazała się bardzo mi pomogła, jest zawijanie danych wejściowych. Oto kod, a za chwilę wyjaśnię, jak to pomaga:

<table>
  <tr>
    <td><div style="overflow:hidden"><input style="width:100%" type="text" name="name" value="hello world" /></div></td>
  </tr>
</table>

Opakowanie DIV INPUT nie ma wypełnienia ani obramowania. To jest rozwiązanie. DIV rozszerzy się do rozmiaru swojego kontenera, ale będzie również przestrzegać obramowania i wypełnienia. Teraz INPUT nie będzie miał problemu z rozszerzeniem do rozmiaru swojego kontenera, ponieważ jest bez obramowania i bez padów. Zauważ również, że DIV ma przepełnienie ustawione na ukryte. Wygląda na to, że domyślnie przedmioty mogą wypadać poza swój pojemnik z domyślnym przepełnieniem widocznym. Zapewnia to tylko, że dane wejściowe pozostają w swoim pojemniku i nie próbują przedrzeć się.

Przetestowałem to w Chrome i Fire Fox. Obaj wydają się dobrze szanować to rozwiązanie.

AKTUALIZACJA : Ponieważ właśnie otrzymałem losowy głos przeciw, chciałbym powiedzieć, że lepszym sposobem radzenia sobie z przepełnieniem jest atrybut rozmiaru pola CSS3, zgodnie z opisem pricco:

.myinput {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -ms-box-sizing: border-box;
    -o-box-sizing: border-box;
    box-sizing: border-box;
}

Wydaje się, że jest to całkiem dobrze obsługiwane przez główne przeglądarki i nie jest „hackem” jak sztuczka z przepełnieniem. Istnieją jednak pewne drobne problemy w obecnych przeglądarkach z tym podejściem (patrz http://caniuse.com/#search=box-sizing Known Issues).

David Peterson
źródło
3
Krótka uwaga: overflow: hidden;treść nadal „przedostaje się” na zewnątrz pudełka w dokładnie ten sam sposób, ale jest obcinana, a nie wyświetlana - więc nie nakłada się na inne treści.
ANeves
2

Wiem, że to pytanie ma już 3 lata, ale problem nadal występuje w obecnych przeglądarkach, a ludzie wciąż tu przychodzą. Na razie rozwiązaniem jest calc () :

input {
    width: calc(100% - 12px); /* IE 9,10 , Chrome, Firefox */
    width: -webkit-calc(100% - 12px); /*For safari 6.0*/
}

Jest obsługiwany przez większość nowoczesnych przeglądarek.

trojański
źródło
1

Problem jest spowodowany modelem bloku elementów wejściowych. Niedawno znalazłem dobre rozwiązanie problemu, gdy starałem się zachować 100% wkładu w przypadku urządzeń mobilnych.

Opakuj dane wejściowe innym elementem, na przykład div. Następnie zastosuj styl, który chcesz wprowadzić, do opakowującego elementu div. Na przykład:

<div class="input-wrapper">
 <input type="text" />
</div>

.input-wrapper {
    border-raius:5px;
    padding:10px;
}
.input-wrapper input[type=text] {
    width:100%;
    font-size:16px;
}

Podaj zaokrąglone narożniki .input-wrapper itp., Cokolwiek chcesz, a następnie podaj szerokość wejściową 100%. Twoje dane wejściowe są ładnie wyściełane obramowaniem itp., Ale bez irytującego przepełnienia!

Hallodom
źródło
1

Naprawiłem ten problem, zaczynając od odpowiedzi @ hallodom. Wszystkie moje dane wejściowe były zawarte w li, więc wszystko, co musiałem zrobić, to ustawić przepełnienie li: ukryte, aby usunąć nadmiar przepełnienia danych wejściowych.

.ie7 form li {
  width:100%;
  overflow:hidden;
}

.ie7 input {
  width:100%;
}
chet
źródło
1

zamiast tej walki o margines, po prostu zrób

input{
    width:100%;
    background:transparent !important;
}

w ten sposób obramowanie komórki jest widoczne i można kontrolować kolor tła wiersza

bortunac
źródło
0

Wyjmij „http://www.w3.org/TR/html4/loose.dtd” z deklaracji DOCTYPE i napraw problem.

Twoje zdrowie! :)

Lucian
źródło
Czy masz na myśli używanie http://www.w3.org/TR/html4/strict.dtdStrict? ref. w3.org/QA/2002/04/valid-dtd-list.html W każdym razie nie jest to opcja, ponieważ zmiana DOCTYPE teraz prawdopodobnie wpłynęłaby na renderowanie wielu innych elementów na stronach internetowych.
Marco Demaio,
0

Za pomocą niektórych Javascript można uzyskać dokładną szerokość zawierającego TD, a następnie przypisać ją bezpośrednio do elementu wejściowego.

Poniżej znajduje się surowy javascript, ale jQuery sprawiłby, że byłby czystszy ...

var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++)
{
    var el = inputs[i];
    if (el.style.width == '100%')
    {
        var pEl = el.parentNode;  // Assumes the parent node is the TD...
        el.style.width = pEl.offsetWidth;
    }
}

Problemy z tym rozwiązaniem to:

1) Jeśli twoje dane wejściowe są zawarte w innym elemencie, takim jak SPAN, będziesz musiał zapętlić się i znaleźć TD, ponieważ elementy takie jak SPAN będą opakowywać dane wejściowe i pokażą jego rozmiar, a nie ograniczając się do rozmiaru TD.

2) Jeśli masz dopełnienie lub marginesy dodane na różnych poziomach, być może będziesz musiał jawnie odjąć to od [pEl.offsetWidth]. W zależności od struktury HTML, którą można obliczyć.

3) Jeśli rozmiar kolumn tabeli jest zmieniany dynamicznie, zmiana rozmiaru jednego elementu spowoduje w niektórych przeglądarkach ponowne przepełnienie tabeli i możesz uzyskać efekt skokowy, gdy kolejno „ustalasz” rozmiary danych wejściowych. Rozwiązaniem jest przypisanie określonych szerokości do kolumny jako wartości procentowe lub piksele LUB zebranie nowych szerokości i ustawienie ich później. Zobacz poniższy kod.

var inputs = document.getElementsByTagName('input');
var newSizes = [];
for (var i = 0; i < inputs.length; i++)
{
    var el = inputs[i];
    if (el.style.width == '100%')
    {
        var pEl = el.parentNode;  // Assumes the parent node is the TD...
        newSizes.push( { el: el, width: pEl.offsetWidth });
    }
}

// Set the sizes AFTER to avoid stepping...
for (var i = 0; i < newSizes.length; i++)
{
    newSizes[i].el.style.width = newSizes[i].width;
}
AnthonyVO
źródło
0

Rozwiązałem problem, aplikując box-sizing:border-box; do samych komórek tabeli, oprócz robienia tego samego z danymi wejściowymi i opakowaniem.

Vanco
źródło
0

Rozwiązałem problem, używając tego

tr td input[type=text] {
  width: 100%;
  box-sizing: border-box;
  -webkit-box-sizing:border-box;
  -moz-box-sizing: border-box;
  background:transparent !important;
  border: 0px;
}
Kevin Muchwat
źródło
-1

Zwykle ustawiam szerokość moich danych wejściowych na 99%, aby to naprawić:

input {
    width: 99%;
}

Możesz także usunąć domyślne style, ale dzięki temu będzie mniej oczywiste, że jest to pole tekstowe. Jednak i tak pokażę kod do tego:

input {
    width: 100%;
    border-width: 0;
    margin: 0;
    padding: 0;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}

Ad @ m

kirb
źródło
-2

Problem tkwi w border-widthelemencie wejściowym. Wkrótce spróbuj ustawić margin-leftelement wejściowy na -2px.

table input {
  margin-left: -2px;
}
burek pekaric
źródło
nie myśl tak. to po prostu przesuwa pudełko w lewo i niszczy lewy margines
cc młody