jQuery-보이지 않을 때 요소의 너비 가져 오기 (디스플레이 : 없음)


108

요소가 보이지 않을 때 jQuery에서 width ()가 0을 반환하는 것 같습니다. 말이되지만 부모를 표시하기 전에 부모의 너비를 설정하려면 테이블의 너비를 가져와야합니다.

아래에서 언급했듯이 부모에는 텍스트가있어 부모가 왜곡되고 불쾌 해 보입니다. 부모가 테이블만큼 넓고 텍스트 줄 바꿈이 있기를 바랍니다.

<div id="parent">
    Text here ... Can get very long and skew the parent
    <table> ... </table>
    Text here too ... which is why I want to shrink the parent based on the table
</div>

CSS :

#parent
{
    display: none;
}

자바 스크립트 :

var tableWidth = $('#parent').children('table').outerWidth();
if (tableWidth > $('#parent').width())
{
    $('#parent').width(tableWidth);
}

tableWidth는 보이지 않기 때문에 항상 0을 반환합니다 (보이는 경우 숫자를 제공하기 때문에 내 추측입니다). 부모를 표시하지 않고 테이블의 너비를 얻는 방법이 있습니까?

답변:


94

여기 내가 사용한 트릭이 있습니다. CSS 속성을 추가하여 jQuery가 요소를 볼 수 있다고 생각하도록 만들지 만 실제로는 여전히 숨겨져 있습니다.

var $table = $("#parent").children("table");
$table.css({ position: "absolute", visibility: "hidden", display: "block" });
var tableWidth = $table.outerWidth();
$table.css({ position: "", visibility: "", display: "" });

일종의 해킹이지만 저에게는 잘 작동하는 것 같습니다.

최신 정보

이 주제를 다루는 블로그 게시물 을 작성했습니다 . 위에서 사용 된 방법은 CSS 속성을 빈 값으로 재설정하기 때문에 문제가 될 수 있습니다. 이전에 가치가 있었다면 어떨까요? 업데이트 된 솔루션은 jQuery 소스 코드에있는 swap () 메서드를 사용합니다.

참조 된 블로그 게시물의 코드 :

//Optional parameter includeMargin is used when calculating outer dimensions  
(function ($) {
$.fn.getHiddenDimensions = function (includeMargin) {
    var $item = this,
    props = { position: 'absolute', visibility: 'hidden', display: 'block' },
    dim = { width: 0, height: 0, innerWidth: 0, innerHeight: 0, outerWidth: 0, outerHeight: 0 },
    $hiddenParents = $item.parents().andSelf().not(':visible'),
    includeMargin = (includeMargin == null) ? false : includeMargin;

    var oldProps = [];
    $hiddenParents.each(function () {
        var old = {};

        for (var name in props) {
            old[name] = this.style[name];
            this.style[name] = props[name];
        }

        oldProps.push(old);
    });

    dim.width = $item.width();
    dim.outerWidth = $item.outerWidth(includeMargin);
    dim.innerWidth = $item.innerWidth();
    dim.height = $item.height();
    dim.innerHeight = $item.innerHeight();
    dim.outerHeight = $item.outerHeight(includeMargin);

    $hiddenParents.each(function (i) {
        var old = oldProps[i];
        for (var name in props) {
            this.style[name] = old[name];
        }
    });

    return dim;
}
}(jQuery));

1
브라우저가 페이지를 두 번 다시 그리지 않습니까? 그렇다면 이것은 차선책입니다.
marcusklaas 2011 년

@Tim Banks 아주 좋아요! 나는 실제로 비슷한 확장을 썼다. 내가 알아 차린 것은 Firefox 에서 매우 이상한 동작 이며 width ()는 귀하와 내 플러그인 모두에 대해 0을 반환합니다. 또한 패딩을 고려하지 않습니다. jsfiddle.net/67cgB . 나는 그것을 고치기 위해 무엇을 할 수 있는지 알아내는 데 가장 어려움을 겪고 있습니다.
Mark Pieszak-Trilon.io 2013 년

숨겨진 아코디언 차원을 얻기 위해 jquery 아코디언 내 에서이 해킹을 어떻게 사용할 수 있습니까? 도움이 필요합니다.
디팍 Ingole

1
@FercoCQ 참조 된 블로그 게시물의 코드를 추가했습니다.
Tim Banks


41
function realWidth(obj){
    var clone = obj.clone();
    clone.css("visibility","hidden");
    $('body').append(clone);
    var width = clone.outerWidth();
    clone.remove();
    return width;
}
realWidth($("#parent").find("table:first"));

더러운 좋은 속임수 !!! 복제본에 올바른 CSS 속성이 있는지 확인합니다 (예 : 원본 요소의 글꼴 크기가 15 인 경우 clone.css ( "visibility", "hidden"). css ( "font-size", "15px"). );)
alex

18
지적하자면 요소가 부모로부터 너비를 상속받은 경우 작동하지 않습니다. 잘못된 신체 너비를 상속합니다.
Dean

3
나는 @Dean이 지적한 문제를 해결 하도록 수정 clone.css("visibility","hidden");했습니다clone.css({"visibility":"hidden", "display":"table"});
isapir

감사합니다! 제 경우에는 약간의 변경으로 작동했습니다. 복제 할 개체와 실제 너비를 얻기 위해 그 안에 선택기를 지원하도록 변경했습니다. 숨겨진 동일한 루트 개체를 항상 측정하는 것은 아닙니다.
falsarella

나는 동일한 접근 방식을 사용했고 그날 많은 반대표를 받았습니다. 당신이 너무 많은 찬성표를 가지고 있다는 것이 이상합니다. 요소를 복사하여 본문에 직접 넣으면이 특정 요소와 관련된 모든 CSS를 제거하는 것입니다. 예를 들면. 이것에서 : #some wrapper .hidden_element{/*Some CSS*/}당신은 이것을 만들고 있습니다 : body .hidden_element. 은 #some_wrapper .hidden_element더 이상 사용되지 않습니다! 결과적으로 계산 된 크기는 원래 크기와 다를 수 있습니다. TLTR : 당신은 스타일을 잃어 버리고 있습니다
대신에

8

Roberts 답변에 따라 여기에 내 기능이 있습니다. 요소 또는 부모가 jQuery를 통해 페이드 아웃 된 경우 내부 또는 외부 치수를 가져올 수 있으며 오프셋 값도 반환 할 수 있습니다.

/ edit1 : 함수를 다시 작성했습니다. 이제 더 작아졌고 객체에서 직접 호출 할 수 있습니다.

/ edit2 :이 함수는 이제 본문 대신 원본 요소 바로 뒤에 복제본을 삽입하여 복제본이 상속 된 차원을 유지할 수 있도록합니다.

$.fn.getRealDimensions = function (outer) {
    var $this = $(this);
    if ($this.length == 0) {
        return false;
    }
    var $clone = $this.clone()
        .show()
        .css('visibility','hidden')
        .insertAfter($this);        
    var result = {
        width:      (outer) ? $clone.outerWidth() : $clone.innerWidth(), 
        height:     (outer) ? $clone.outerHeight() : $clone.innerHeight(), 
        offsetTop:  $clone.offset().top, 
        offsetLeft: $clone.offset().left
    };
    $clone.remove();
    return result;
}

var dimensions = $('.hidden').getRealDimensions();

그것을 필요로하는 사람들을위한 YUI 버전 : gist.github.com/samueljseay/13c2e69508563b2f0458
코드 수련원

'실제'항목이 아니라 복제품이라는 점을 감안할 때 offsetTop이 항목에 맞습니까? $ this.offset (). top을 사용해야합니까? 또한 상단 / 왼쪽을 무엇에 사용하고 있는지 궁금하십니까? 나는 '너비'만 사용하고 있지만 어떤 이유로 이러한 오프셋을 염려 해야하는지 궁금합니다.
Terry

3

위의 realWidth 함수를 게시 해 주셔서 감사합니다. 정말 도움이되었습니다. 위의 "realWidth"함수를 기반으로 CSS 재설정 (아래에 설명 된 이유)을 작성했습니다.

function getUnvisibleDimensions(obj) {
    if ($(obj).length == 0) {
        return false;
    }

    var clone = obj.clone();
    clone.css({
        visibility:'hidden',
        width : '',
        height: '',
        maxWidth : '',
        maxHeight: ''
    });
    $('body').append(clone);
    var width = clone.outerWidth(),
        height = clone.outerHeight();
    clone.remove();
    return {w:width, h:height};
}

"realWidth"는 기존 태그의 너비를 가져옵니다. 몇 가지 이미지 태그로 이것을 테스트했습니다. 문제는 이미지가 너비 당 CSS 크기 (또는 최대 너비)를 지정하면 해당 이미지의 실제 크기를 얻을 수 없다는 것입니다. 아마도 img에는 ​​"max-width : 100 %"가 있고 "realWidth"함수는이를 복제하여 본문에 추가합니다. 이미지의 원래 크기가 본문보다 크면 해당 이미지의 실제 크기가 아닌 본문 크기를 얻습니다.


3

숨겨진 요소에 대한 작동 기능을 찾으려고 노력하지만 CSS가 모든 사람이 생각하는 것보다 훨씬 복잡하다는 것을 알고 있습니다. CSS3에는 유연한 상자, 그리드, 열 또는 복잡한 상위 요소 내부의 요소와 같은 모든 이전 답변에서 작동하지 않을 수있는 많은 새로운 레이아웃 기술이 있습니다.

flexibox 예 여기에 이미지 설명 입력

지속 가능하고 간단한 유일한 해결책은 실시간 렌더링 이라고 생각합니다 . 이때 브라우저는 올바른 요소 크기를 제공해야합니다 .

안타깝게도 JavaScript는 요소가 표시되거나 숨겨 질 때 알리는 직접적인 이벤트를 제공하지 않습니다. 하지만 요소의 가시성이 변경되면 콜백 함수를 실행하는 DOM Attribute Modified API를 기반으로 일부 함수를 생성합니다.

$('[selector]').onVisibleChanged(function(e, isVisible)
{
    var realWidth = $('[selector]').width();
    var realHeight = $('[selector]').height();

    // render or adjust something
});

자세한 내용은 내 프로젝트 GitHub를 방문하십시오.

https://github.com/Soul-Master/visible.event.js

데모 : http://jsbin.com/ETiGIre/7


4
CSS는 모든 사람들이 생각하는 것보다 훨씬 복잡하다 ... 이것은 매우 사실이다
dgellow

3

숨겨진 무언가의 너비가 필요하고 어떤 이유로 든 숨기기를 해제 할 수없는 경우이를 복제하고 CSS를 변경하여 페이지에 표시되지 않도록 설정 한 다음 측정 할 수 있습니다. 나중에 숨기고 삭제하면 사용자는 현명하지 않습니다.

여기에있는 다른 답변 중 일부는 가시성을 숨겨서 작동하지만 페이지에서 몇 분의 1 초 동안 공백을 차지합니다.

예:

$itemClone = $('.hidden-item').clone().css({
        'visibility': 'hidden',
        'position': 'absolute',
        'z-index': '-99999',
        'left': '99999999px',
        'top': '0px'
    }).appendTo('body');
var width = $itemClone.width();
$itemClone.remove();

2
요소 크기가 레이아웃 계층 구조를 기반으로 상위 컨테이너 또는 더 복잡한 CSS 선택기의 영향을받는 경우 작동하지 않습니다.
Sebastian Nowak

2

너비를 취하기 전에 부모 디스플레이를 표시 한 다음 너비를 취하고 마지막으로 부모 디스플레이를 숨 깁니다. 다음과 같이

$('#parent').show();
var tableWidth = $('#parent').children('table').outerWidth();
 $('#parent').hide();
if (tableWidth > $('#parent').width())
{
    $('#parent').width() = tableWidth;
}

2

모든 상황에서 작동하지는 않지만 한 가지 해결책은 불투명도를 0으로 설정하여 요소를 숨기는 것입니다. 완전히 투명한 요소에는 너비가 있습니다.

단점은 요소가 여전히 공간을 차지하지만 모든 경우에 문제가되지는 않는다는 것입니다.

예를 들면 :

$(img).css("opacity", 0)  //element cannot be seen
width = $(img).width()    //but has width

1

대부분의 솔루션에서 놓친 가장 큰 문제는 요소의 너비가 html에서 범위가 지정된 위치에 따라 CSS에 의해 자주 변경된다는 것입니다.

현재 범위에만 적용되는 스타일이있을 때 본문에 복제본을 추가하여 요소의 offsetWidth를 결정하면 잘못된 너비를 얻게됩니다.

예를 들면 :

// css

.module-container .my-elem {테두리 : 60px 단색 검정; }

이제 신체의 맥락에서 my-elem의 너비를 결정하려고하면 120px가됩니다. 대신 모듈 컨테이너를 복제 할 수 있지만 JS는 이러한 세부 정보를 알 필요가 없습니다.

나는 그것을 테스트하지 않았지만 본질적으로 Soul_Master의 솔루션이 제대로 작동 할 수있는 유일한 솔루션 인 것 같습니다. 그러나 불행히도 구현을 살펴보면 사용 비용이 많이 들고 성능에 좋지 않을 수 있습니다 (여기에 제시된 대부분의 솔루션도 마찬가지 임).

가능하다면 visible : hidden을 대신 사용하세요. 그래도 요소를 렌더링하므로 번거 로움없이 너비를 계산할 수 있습니다.


0

내 문제를 해결 한 후 Tim Banks가 게시 한 답변 외에도 간단한 한 가지를 편집해야했습니다.

다른 사람도 같은 문제를 겪을 수 있습니다. 드롭 다운에서 부트 스트랩 드롭 다운으로 작업하고 있습니다. 그러나이 시점에서 텍스트는 현재 콘텐츠보다 더 넓을 수 있습니다 (그리고 CSS를 통해 문제를 해결할 수있는 좋은 방법은 많지 않습니다).

나는 사용했다 :

$table.css({ position: "absolute", visibility: "hidden", display: "table" });

대신 내용이 더 넓은 경우 항상 너비가 조정되는 테이블로 컨테이너를 설정합니다.


0
jQuery(".megamenu li.level0 .dropdown-container .sub-column ul .level1").on("mouseover", function () {
    var sum = 0;
    jQuery(this).find('ul li.level2').each(function(){
    sum -= jQuery(this).height();
    jQuery(this).parent('ul').css('margin-top', sum / 1.8);
    console.log(sum);
    });
});

마우스 오버시 목록 항목 높이를 계산할 수 있습니다.


0

이전에 언급했듯이 복제 및 다른 곳에 연결 방법은 스타일이 다를 수 있으므로 동일한 결과를 보장하지 않습니다.

아래는 내 접근 방식입니다. 은신을 담당하는 부모를 찾는 부모를 위로 이동 한 다음 일시적으로 숨김을 해제하여 필요한 너비, 높이 등을 계산합니다.

    var width = parseInt($image.width(), 10);
    var height = parseInt($image.height(), 10);

    if (width === 0) {

        if ($image.css("display") === "none") {

            $image.css("display", "block");
            width = parseInt($image.width(), 10);
            height = parseInt($image.height(), 10);
            $image.css("display", "none");
        }
        else {

            $image.parents().each(function () {

                var $parent = $(this);
                if ($parent.css("display") === "none") {

                    $parent.css("display", "block");
                    width = parseInt($image.width(), 10);
                    height = parseInt($image.height(), 10);
                    $parent.css("display", "none");
                }
            });
        }
    }

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.