Introduzindo uma imagem padrão, caso o atributo src de um html <img> não seja válido?

268

Existe alguma maneira de renderizar uma imagem padrão em uma <img>tag HTML , caso o srcatributo seja inválido (usando apenas HTML)? Caso contrário, qual seria sua maneira mais leve de contornar isso?

Galilyou
fonte
3
HTML não tem substituto para imagens quebradas. Você precisaria usar o JavaScript para encontrar imagens quebradas e alterar o atributo src.
Blixt
2
@Blixt - O que se seu cliente for MS Outlook ou o leitor EMAIL someother e você não tem Javascript, ea opção objeto não trabalho ... Eu presumo que a única solução é alt / text
Xofo

Respostas:

319

Você solicitou uma solução somente HTML ...

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">

<head>
  <title>Object Test</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>

<body>

  <p>
    <object data="http://stackoverflow.com/does-not-exist.png" type="image/png">
      <img src="https://cdn.sstatic.net/Img/unified/sprites.svg?v=e5e58ae7df45" alt="Stack Overflow logo and icons and such">
    </object>
  </p>

</body>

</html>

Como a primeira imagem não existe, o fallback (os sprites usados ​​neste site *) será exibido. E se você estiver usando um navegador realmente antigo que não suporta object, ele ignorará essa tag e a usará img. Consulte o site da caniuse para obter compatibilidade. Este elemento é amplamente suportado por todos os navegadores do IE6 +.

* A menos que o URL da imagem seja alterado (novamente), nesse caso, você provavelmente verá o texto alternativo.

Patrick McElhaney
fonte
3
Funcionou para mim no IE8 depois de inserir o DTD para HTML 4.01.
22320 Patrick McElhaney
Isso não funciona se a imagem inexistente tiver sido X-Frame-Optionsdefinida como SAMEORIGINou uma configuração mais permissiva.
Attila O.
Ele funciona, mas se o link em object.data não é confiável, ele pode carregar todo o tipo de coisas ...
Michael_Scharf
1
O elemento 'img' não pode ser aninhado dentro do elemento 'objeto'.
Matheus Miranda
2
@ Matheus Claro que pode. No HTML4, o objeto pode conter conteúdo de fluxo (quase tudo, inclusive img), e no HTML5 é transparente, o que significa que pode conter qualquer HTML5 válido.
Patrick McElhaney
318

Isto funciona bem para mim. Talvez você queira usar o JQuery para conectar o evento.

 <img src="foo.jpg" onerror="if (this.src != 'error.jpg') this.src = 'error.jpg';">

Atualizado com o protetor de erro jacquargs

Atualizado: solução somente CSS Eu vi recentemente a demonstração de Vitaly Friedman uma ótima solução CSS que eu não conhecia. A idéia é aplicar a contentpropriedade à imagem quebrada. Normalmente :afterou :beforenão se aplicam a imagens, mas quando estão quebradas, são aplicadas.

<img src="nothere.jpg">
<style>
img:before {
    content: ' ';
    display: block;
    position: absolute;
    height: 50px;
    width: 50px;
    background-image: url(ishere.jpg);
</style>

Demonstração: https://jsfiddle.net/uz2gmh2k/2/

Como o violino mostra, a imagem quebrada em si não é removida, mas isso provavelmente resolverá o problema na maioria dos casos, sem JS e sem CSS. Se você precisar aplicar imagens diferentes em locais diferentes, basta diferenciar com uma classe:.my-special-case img:before { ...

Svend
fonte
3
Na minha opinião. Essa é a melhor resposta. Aqui estão os modos peculiares de assumir um erro ... parece bastante seguro para mim. quirksmode.org/dom/events/error.html#t01
n0nag0n
12
BTW, se error.jpg não existir, isso causa um loop infinito, porque ele continua tentando encontrar a imagem; onError é chamado novamente, não é possível encontrá-lo e tudo começa novamente.
#
30
Para evitar riscos de loop infinito, basta adicionar um teste: <img src = "foo.jpg" onerror = "if (this.src! = 'Error.jog') this.src = 'error.jpg';">
jacquarg
21
Como alternativa, você pode escrever:onerror="this.src='error.jpg';this.onerror='';"
Denilson Sá Maia
6
Onde está o jQuery nisso?
Praveen Kumar Purushothaman
64

Encontrei esta solução no Spring in Action 3rd Ed.

<img src="../resources/images/Image1.jpg" onerror="this.src='../resources/images/none.jpg'" />

Atualização: Esta não é uma solução apenas para HTML ... onerroré javascript

amit bakle
fonte
3
Isso funciona muito bem. Aqui está uma atualização com uma imagem de fallback no imgur: <img src = "a-falta-imagem.jpg" alt = "" onerror = "this.src = 'http: ///i.imgur.com/hfM1J8s.png' ">
arpo
15

<img style="background-image: url(image1), url(image2);"></img>                                            

Use a imagem de fundo que permite adicionar várias imagens. Meu caso: image1 é a imagem principal; isso será obtido em algum lugar (navegador fazendo uma solicitação) image2 é uma imagem local padrão a ser exibida enquanto a imagem1 está sendo carregada. Se a imagem1 retornar algum tipo de erro, o usuário não verá nenhuma alteração e isso ficará limpo para a experiência do usuário

Emiliano Barboza
fonte
Isso funciona apenas se a imagem1 for completamente opaca. Se tiver transparência, como a maioria das imagens de ícones, a imagem2 será exibida.
Jdunning 29/07
14
<style type="text/css">
img {
   background-image: url('/images/default.png')
}
</style>

Certifique-se de inserir as dimensões da imagem e se deseja que a imagem seja ladrilhada ou não.

lambacck
fonte
28
A maioria dos navegadores não mostra uma imagem de 'link quebrado' quando a imagem não é encontrada ... Nesse caso, definir o plano de fundo não resolveria o problema.
Justin D.
13

Eu não acho que é possível usar apenas HTML. No entanto, usando javascript, isso deve ser possível. Em baixo, percorremos cada imagem, testamos se ela está completa e se a largura natural é zero, isso significa que ela não foi encontrada. Aqui está o código:

fixBrokenImages = function( url ){
    var img = document.getElementsByTagName('img');
    var i=0, l=img.length;
    for(;i<l;i++){
        var t = img[i];
        if(t.naturalWidth === 0){
            //this image is broken
            t.src = url;
        }
    }
}

Use-o assim:

 window.onload = function() {
    fixBrokenImages('example.com/image.png');
 }

Testado no Chrome e Firefox

Pim Jager
fonte
2
Ele está funcionando com o Pim e é totalmente reutilizável, mas eu preferiria a opção leve para esse mesmo caso. Muito obrigado :) +1
Galilyou
Você salvou toda a minha vida, senhor.
Beardminator
12

Se você estiver usando Angular / jQuery, isso pode ajudar ...

<img ng-src="{{item.url}}" altSrc="{{item.alt_url}}" onerror="this.src = $(this).attr('altSrc')">

Explicação

Supondo que itemtenha uma propriedade urlque possa ser nula, quando estiver, a imagem aparecerá como quebrada. Isso aciona a execução da onerrorexpressão de atributo, conforme descrito acima. Você precisa substituir o srcatributo conforme descrito acima, mas precisará do jQuery para acessar seu altSrc. Não foi possível fazê-lo funcionar com JavaScript de baunilha.

Pode parecer um pouco hacky, mas salvou o dia no meu projeto.

Obie
fonte
11

um simples elemento img não é muito flexível, então eu o combinei com um elemento de imagem. dessa forma, nenhum CSS é necessário. quando ocorre um erro, todos os srcset são definidos para a versão de fallback. uma imagem de link quebrado não está aparecendo. ele não carrega versões de imagem desnecessárias. o elemento picture suporta design responsivo e vários fallbacks para tipos que não são suportados pelo navegador.

<picture>
    <source id="s1" srcset="image1_not_supported_by_browser.webp" type="image/webp">
    <source id="s2" srcset="image2_broken_link.png" type="image/png">
    <img src="image3_fallback.jpg" alt="" onerror="this.onerror=null;document.getElementById('s1').srcset=document.getElementById('s2').srcset=this.src;">
</picture>
bapho
fonte
esse é ótimo! esteja atento ao suporte ao navegador ausente caniuse.com/#feat=picture . considere usar um polyfill ou outra solução se precisar oferecer suporte a navegadores mais antigos como o IE11.
Hinrich
7

angular2:

<img src="{{foo.url}}" onerror="this.src='path/to/altimg.png'">
user3601578
fonte
1
Embora isso possa funcionar, acho que não adiciona nenhuma informação nova. A parte onerror é apenas baunilha JavaScript eo src ligação já deve ser conhecido pelos usuários angular
Chic
7

Solução simples e limpa, envolvendo boas respostas e comentários.

<img src="foo.jpg" onerror="this.src='error.jpg';this.onerror='';">

Ele até resolve o risco de loop infinito.

Trabalhou para mim.

manish kumar
fonte
IMO, isso definitivamente não parece elegante.
Script47
1
@ Script47 Seu puro, repito puro
Manish Kumar
1
Não, eu também não diria que é legal. Sem mencionar que esta é provavelmente uma reformulação de outras soluções.
Script47
Funciona como um encanto! Obrigado!
Goehybrid #
1
Lifesaver. Não queria elegante, queria simples e trabalhadora. Obrigado!
Kit
7

Uma solução apenas para HTML, onde o único requisito é que você saiba o tamanho da imagem que está inserindo. Não funcionará para imagens transparentes, pois é usado background-imagecomo preenchimento.

Podemos usar background-imagecom êxito para vincular a imagem que aparece se a imagem fornecida estiver ausente. Então, o único problema é a imagem quebrada do ícone - podemos removê-la inserindo um caractere vazio muito grande, empurrando o conteúdo para fora da tela de img.

img {
  background-image: url("http://placehold.it/200x200");
  overflow: hidden;
}

img:before {
  content: " ";
  font-size: 1000px;
}
This image is missing:
<img src="a.jpg" style="width: 200px; height: 200px"/><br/>
And is displaying the placeholder


Uma solução somente CSS (apenas Webkit)

img:before {
  content: " ";
  font-size: 1000px;
  background-image: url("http://placehold.it/200x200");
  display: block;
  width: 200px;
  height: 200px;
  position: relative;
  z-index: 0;
  margin-bottom: -16px;
}
This image is there:
<img src="http://placehold.it/100x100"/><br/>

This image is missing:
<img src="a.jpg"/><br/>
And is displaying the placeholder

eithed
fonte
4

Não há como ter certeza do grande número de clientes (navegadores) que tentarão exibir sua página. Um aspecto a considerar é que os clientes de email são navegadores da web padrão e podem não lidar com tais truques de truques ...

Como tal, você também deve incluir um texto alternativo com uma LARGURA E ALTURA PADRÃO, assim. Esta é uma solução HTML pura.

alt="NO IMAGE" width="800" height="350"

Portanto, a outra boa resposta seria ligeiramente modificada da seguinte maneira:

<img src="foo.jpg" onerror="if (this.src != 'error.jpg') this.src = 'error.jpg';" alt="NO IMAGE" width="800" height="350">

Eu tive problemas com a tag de objeto no Chrome, mas imagino que isso se aplicaria a isso também.

Você pode estilizar ainda mais o alt / texto para ser MUITO GRANDE ...

Portanto, minha resposta é usar Javascript com um bom retorno alternativo para texto / alt.

Também achei isso interessante: Como estilizar o atributo alt de uma imagem

Xofo
fonte
3

Uma versão modulável com JQuery , adicione isso no final do seu arquivo:

<script>
    $(function() {
        $('img[data-src-error]').error(function() {
            var o = $(this);
            var errorSrc = o.attr('data-src-error');

            if (o.attr('src') != errorSrc) {
                o.attr('src', errorSrc);
            }
        });
    });
</script>

e na sua imgtag:

<img src="..." data-src-error="..." />
Kevin Robatel
fonte
3

A solução acima está incompleta , perdeu o atributo src.

this.srce this.attribute('src')NÃO são iguais, o primeiro contém a referência completa à imagem, por exemplo http://my.host/error.jpg, mas o atributo apenas mantém o valor original,error.jpg

Solução correta

<img src="foo.jpg" onerror="if (this.src != 'error.jpg' && this.attribute('src') != 'error.jpg') this.src = 'error.jpg';" />
Seb
fonte
3
Ao usar este código, eu vejo Uncaught TypeError: this.attribute is not a functionno Chrome 43.
John Washam
Você está usando jQuery?
mix3d
O onError está obsoleto de acordo com developer.mozilla.org/pt-BR/docs/Web/HTML/Element/img
comiventor
2

Se você estiver usando o Angular 1.x, poderá incluir uma diretiva que permita o retorno a qualquer número de imagens. O atributo fallback suporta um único URL, vários URLs dentro de uma matriz ou uma expressão angular usando dados de escopo:

<img ng-src="myFirstImage.png" fallback="'fallback1.png'" />
<img ng-src="myFirstImage.png" fallback="['fallback1.png', 'fallback2.png']" />
<img ng-src="myFirstImage.png" fallback="myData.arrayOfImagesToFallbackTo" />

Adicione uma nova diretiva de fallback ao seu módulo de aplicativo angular:

angular.module('app.services', [])
    .directive('fallback', ['$parse', function ($parse) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                var errorCount = 0;

                // Hook the image element error event
                angular.element(element).bind('error', function (err) {
                    var expressionFunc = $parse(attrs.fallback),
                        expressionResult,
                        imageUrl;

                    expressionResult = expressionFunc(scope);

                    if (typeof expressionResult === 'string') {
                        // The expression result is a string, use it as a url
                        imageUrl = expressionResult;
                    } else if (typeof expressionResult === 'object' && expressionResult instanceof Array) {
                        // The expression result is an array, grab an item from the array
                        // and use that as the image url
                        imageUrl = expressionResult[errorCount];
                    }

                    // Increment the error count so we can keep track
                    // of how many images we have tried
                    errorCount++;
                    angular.element(element).attr('src', imageUrl);
                });
            }
        };
    }])
Rob Evans
fonte
Idéia legal! Uma matriz off imagens de fallback é uma boa implementação
Z. Khullah
1

Recentemente, tive que criar um sistema de fallback que incluísse qualquer número de imagens de fallback. Aqui está como eu fiz isso usando uma função JavaScript simples.

HTML

<img src="some_image.tiff"
    onerror="fallBackImg(this);"
    data-fallIndex="1"
    data-fallback1="some_image.png"
    data-fallback2="some_image.jpg">

Javascript

function fallBackImg(elem){
    elem.onerror = null;
    let index = +elem.dataset.fallIndex;
    elem.src = elem.dataset[`fallback${index}`];
    index++;
    elem.dataset.fallbackindex = index;
}

Sinto que é uma maneira bastante leve de lidar com muitas imagens de fallback.

Rager
fonte
O onError está obsoleto de acordo com developer.mozilla.org/pt-BR/docs/Web/HTML/Element/img
comiventor 16/03
0

Usando o Jquery, você poderia fazer algo assim:

$(document).ready(function() {
    if ($("img").attr("src") != null)
    {
       if ($("img").attr("src").toString() == "")
       {
            $("img").attr("src", "images/default.jpg");
       }
    }
    else
    {
        $("img").attr("src", "images/default.jpg");
    }
});
Jon
fonte
0

Para qualquer imagem, basta usar este código javascript:

if (ptImage.naturalWidth == 0)
    ptImage.src = '../../../../icons/blank.png';

onde ptImageé um <img>endereço de tag obtido por document.getElementById().

José Esteves Pereira
fonte
0

O Google lançou esta página com as palavras-chave "image fallback html", mas como as opções acima não me ajudaram, e eu estava procurando por um "suporte de fallback svg para o IE abaixo de 9", continuei pesquisando e foi isso que descobri:

<img src="base-image.svg" alt="picture" />
<!--[if (lte IE 8)|(!IE)]><image src="fallback-image.png" alt="picture" /><![endif]-->

Pode ser fora do tópico, mas resolveu meu próprio problema e também pode ajudar outra pessoa.

Sándor Zuboly
fonte
0

Além da brilhante resposta de Patrick , para aqueles que procuram uma solução js angular de plataforma cruzada, aqui está:

<object type="image/png" data-ng-attr-data="{{ url || 'data:' }}">
    <!-- any html as a fallback -->
</object>

Aqui está uma brincadeira em que eu estava jogando, tentando encontrar a solução certa: http://plnkr.co/edit/nL6FQ6kMK33NJeW8DVDY?p=preview

sunsay
fonte
0

Se você criou um projeto dinâmico da Web e colocou a imagem necessária no WebContent, pode acessar a imagem usando o código abaixo mencionado no Spring MVC:

<img src="Refresh.png" alt="Refresh" height="50" width="50">

Você também pode criar uma pasta chamada img e colocar a imagem dentro da pasta img e colocar a pasta img dentro do WebContent para acessar a imagem usando o código abaixo mencionado:

<img src="img/Refresh.png" alt="Refresh" height="50" width="50">
Yoshita Mahajan
fonte
-2

Bem!! Achei isso conveniente, verifique se o atributo height da imagem é 0 e, em seguida, você pode substituir o atributo src pela imagem padrão: https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/ Imagem

 image.setAttribute('src','../icons/<some_image>.png');
  //check the height attribute.. if image is available then by default it will 
  //be 100 else 0
  if(image.height == 0){                                       
       image.setAttribute('src','../icons/default.png');
  }
suhail
fonte