src가 없는 img 요소 대체하기 (pseudo-element, safari 해결방법)

한땀코딩 2023. 3. 26. 16:56

문제

어떤 배경 상황이 있을지는 사람마다 다르겠지만 HTML img 요소에 src의 값이 빈 문자열인 경우 대체 이미지를 띄우고 싶은 상황이 있다고 가정해 봅시다. 대체용 이미지를 만들어두고 집어넣을 수도 있겠지만 제 경우 별도로 파일을 관리하기도 귀찮았고, inline으로 이미지의 사이즈가 주어지는 경우도 있어 고정된 사이즈의 이미지를 사용하면 비율이 엉망이 될 가능성이 높았습니다.

검색과 chat GPT의 도움을 받아 방법을 찾아보던 중, 단지 css 만으로도 이 문제를 해결할 수 있다는 놀라운 사실을 알게 되어 글을 작성해보려고 합니다.

물론 세련된 디자인을 원하신다면 적절하지 않을 수도 있으나 정적 파일이나 JS 조작이 없다는 점에서 다른 비슷한 문제 해결에도 참고가 될 수 있을 거 같습니다.

코드

src가 빈 문자열인 img 찾기

css selector에선 attribute를 기준으로도 요소에 접근할 수 있습니다. 대체 이미지를 적용하고 싶은 img 요소는 src 속성이 빈 문자열이기 때문에 css에서 다음과 같이 적어 탐색할 수 있습니다.

img[src='']

이처럼 속성을 통한 접근 방식은 상당히 다양한데 (특정 속성이 없는 요소, 특정 속성의 값이 정규표현식을 만족하는 경우 등등) 더 다양한 selector는 Attribute Selector 페이지에서 확인이 가능합니다.

inline-block

img는 본질적으로는 inline 요소라 직접적으로 width, height 설정이 불가합니다. pseudo-element를 넣어서 이 img 요소의 height, width100%로 맞춰주고 싶기 때문에 inline-block으로 바꿔주어야 합니다.

pseudo-element

의사 요소는 선택한 요소의 특정 영역에 원하는 스타일을 적용시켜 줍니다. 쉽게 생가하면, html에 직접 요소를 추가하지 않아도, css selector 선택한 요소의 특정 위치에 임시로 요소를 추가해 줍니다.

이번 문제를 해결하기 위해서 저는 src가 빈 문자열인 이미지 위에 position absolute인 요소를 하나 생성해서 덮어주기로 했습니다. 배경색을 원하는 것으로 지정하고 content에 원하는 텍스트를 넣어주면 이미지의 사이즈와 동일한 박스 하나가 자리를 대신하게 됩니다. 위에 덮어써야 하기 때문에 선택한 요소 바로 앞에 요소를 추가해 주는 ::before 의사 요소를 사용했습니다.

img[src='']::before {
  content: 'image';

  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 0;
  left: 0;
  background-color: blue;
  width: 100%;
  height: 100%;
  font-size: 10pt;
  color: white;
  overflow: hidden;
}

만일 다른 텍스트를 사용하고 싶다면 content 값을 바꿔주면 됩니다. 여기는 단순 문자열만이 아니라 선택한 요소의 속성에서도 값을 가져올 수 있습니다. 예를 들어 저 img에 custom 속성으로 replace-text가 있고 해당 속성의 값이 ‘no-image’라고 가정해 봅시다. content에 이 ‘no-image’라는 문자열을 넣고 싶다면 다음과 같이 작성할 수 있습니다.

img[src='']::before {
  content: attr(replace-text);
}

혹시 Safari에서는 확인해 보셨나요?

……?

혹시나 했는데 역시나 Safari였습니다. 확인해 보면 의사요소 자체가 아예 없어져있습니다. 정확히 명시된 문서는 찾지 못했으나, Safari에서 replaced element 에는 의사 요소 ::before::after가 적용되지 않는다는 말이 있었습니다. (w3의 css2 문서에 관련된 언급은 있습니다.)

replaced element?

이번 문제를 해결하면서 처음 접하게 된 단어였습니다. MDN에서 가져온 대체 요소의 정의입니다.

자신의 표현 결과가 CSS의 범위를 벗어나는 요소로서, CSS 서식 모델과는 분리된 외부 객체인 요소입니다.
간단히 말해서, 대체 요소는 자신의 콘텐츠가 현재 문서 스타일의 영향을 받지 않는 요소라고 할 수 있습니다.

img 요소의 실제 콘텐츠는 css로 지정하지 않기 때문에 대표적인 대체 요소라 볼 수 있습니다.

해결방법

가장 좋은 방법은 본질적인 문제를 해결해서 src를 빈 문자열로 남기지 않는 것이겠지만 위에서 서술한 것과 비슷한 방법으로 해결하기 위해서는 img 요소를 다른 요소로 한번 감싼 뒤 css를 적용해 주는 것입니다. 물론 이렇게 다른 요소를 추가하기 위해선 JS가 필요하거나 사전에 HTML을 수정해 주는 작업이 필요할 수 있어 상황에 따라 적용이 어려울 수도 있습니다.

코드